Skip to content

Commit 02d8e1f

Browse files
committed
Updates for Service Instance & Bindings
Updates for service instances. Prep to allow updates to chosen parameters for instance and bindings.
1 parent bba7c7f commit 02d8e1f

File tree

12 files changed

+891
-49
lines changed

12 files changed

+891
-49
lines changed

app/index.html

+2
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ <h1>JavaScript Required</h1>
255255
<script src="scripts/controllers/statefulSet.js"></script>
256256
<script src="scripts/controllers/services.js"></script>
257257
<script src="scripts/controllers/service.js"></script>
258+
<script src="scripts/controllers/provisionedServices.js"></script>
259+
<script src="scripts/controllers/provisionedService.js"></script>
258260
<script src="scripts/controllers/secrets.js"></script>
259261
<script src="scripts/controllers/secret.js"></script>
260262
<script src="scripts/controllers/createSecret.js"></script>

app/scripts/app.js

+10
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ angular
271271
controller: 'ServiceController',
272272
reloadOnSearch: false
273273
})
274+
.when('/project/:project/browse/service-instances', {
275+
templateUrl: 'views/provisioned.html',
276+
controller: 'ProvisionedServicesController',
277+
reloadOnSearch: false
278+
})
279+
.when('/project/:project/browse/service-instances/:instance', {
280+
templateUrl: 'views/browse/provisioned-service.html',
281+
controller: 'ProvisionedServiceController',
282+
reloadOnSearch: false
283+
})
274284
.when('/project/:project/browse/storage', {
275285
templateUrl: 'views/storage.html',
276286
controller: 'StorageController',

app/scripts/constants.js

+14
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,20 @@ angular.extend(window.OPENSHIFT_CONSTANTS, {
190190
prefixes: [
191191
"/browse/routes/"
192192
]
193+
},
194+
{
195+
label: "Provisioned Services",
196+
href: "/browse/service-instances",
197+
prefixes: [
198+
"/browse/service-instances/"
199+
],
200+
isValid: function(){
201+
return _.get(window.OPENSHIFT_CONSTANTS, 'ENABLE_TECH_PREVIEW_FEATURE.service_catalog_landing_page');
202+
},
203+
canI: {
204+
resource: 'rolebindings',
205+
verb: 'list'
206+
}
193207
}
194208
]
195209
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use strict';
2+
3+
angular.module('openshiftConsole')
4+
.controller('ProvisionedServiceController', function ($scope,
5+
$filter,
6+
$routeParams,
7+
DataService,
8+
ProjectsService) {
9+
$scope.alerts = {};
10+
$scope.displayName = null;
11+
$scope.projectName = $routeParams.project;
12+
$scope.serviceInstance = null;
13+
$scope.serviceInstances = null;
14+
$scope.serviceClasses = {};
15+
16+
$scope.breadcrumbs = [
17+
{
18+
title: "Provisioned Services",
19+
link: "project/" + $routeParams.project + "/browse/service-instances"
20+
},
21+
{
22+
title: $routeParams.instance
23+
}
24+
];
25+
26+
var watches = [];
27+
28+
var setDisplayName = function() {
29+
if(!$scope.serviceInstance || !$scope.serviceClasses) {
30+
return;
31+
}
32+
33+
$scope.displayName = $filter('serviceInstanceDisplayName')($scope.serviceInstance, $scope.serviceClasses);
34+
};
35+
36+
var serviceResolved = function(service, action) {
37+
$scope.loaded = true;
38+
$scope.serviceInstance = service;
39+
40+
if (action === "DELETED") {
41+
$scope.alerts["deleted"] = {
42+
type: "warning",
43+
message: "This provisioned service has been deleted."
44+
};
45+
}
46+
};
47+
48+
ProjectsService
49+
.get($routeParams.project)
50+
.then(_.spread(function(project, context) {
51+
$scope.project = project;
52+
$scope.projectContext = context;
53+
54+
DataService
55+
.get({
56+
group: 'servicecatalog.k8s.io',
57+
resource: 'instances'
58+
}, $routeParams.instance, context, { errorNotification: false })
59+
.then(function(service) {
60+
serviceResolved(service);
61+
setDisplayName();
62+
watches.push(DataService.watchObject({
63+
group: 'servicecatalog.k8s.io',
64+
resource: 'instances'
65+
}, $routeParams.instance, context, serviceResolved));
66+
67+
}, function(error) {
68+
$scope.loaded = true;
69+
$scope.alerts["load"] = {
70+
type: "error",
71+
message: "The service details could not be loaded.",
72+
details: $filter('getErrorDetails')(error)
73+
};
74+
});
75+
76+
DataService.list({
77+
group: 'servicecatalog.k8s.io',
78+
resource: 'serviceclasses'
79+
}, context, function(serviceClasses) {
80+
$scope.serviceClasses = serviceClasses.by('metadata.name');
81+
setDisplayName();
82+
});
83+
84+
watches.push(DataService.watch({
85+
group: 'servicecatalog.k8s.io',
86+
resource: 'instances'
87+
}, context, function(services) {
88+
$scope.serviceInstances = services.by("metadata.name");
89+
}));
90+
91+
$scope.$on('$destroy', function(){
92+
DataService.unwatchAll(watches);
93+
});
94+
95+
}));
96+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
'use strict';
2+
3+
angular.module('openshiftConsole')
4+
.controller('ProvisionedServicesController', function ($scope,
5+
$filter,
6+
$routeParams,
7+
APIService,
8+
BindingService,
9+
Constants,
10+
DataService,
11+
LabelFilter,
12+
Logger,
13+
ProjectsService) {
14+
$scope.alerts = $scope.alerts || {};
15+
$scope.applicationsByBinding = {};
16+
$scope.bindings = {};
17+
$scope.bindableServiceInstances = {};
18+
//$scope.bindingsByApplicationUID = {};
19+
$scope.bindingsByInstanceRef = {};
20+
$scope.emptyMessage = "Loading...";
21+
$scope.labelSuggestions = {};
22+
//$scope.notificationsByObjectUID = {};
23+
$scope.projectName = $routeParams.project;
24+
$scope.serviceClasses = {};
25+
$scope.serviceInstances = {};
26+
$scope.unfilteredServiceInstances = {};
27+
28+
var watches = [];
29+
30+
/*var getUID = function(apiObject) {
31+
return _.get(apiObject, 'metadata.uid');
32+
};
33+
34+
var setNotifications = function(apiObject, notifications) {
35+
var uid = getUID(apiObject);
36+
$scope.notificationsByObjectUID[uid] = notifications || {};
37+
};
38+
39+
var getNotifications = function(apiObject) {
40+
var uid = getUID(apiObject);
41+
if (!uid) {
42+
return {};
43+
}
44+
return _.get(state, ['notificationsByObjectUID', uid], {});
45+
};*/
46+
47+
var updateFilter = function() {
48+
$scope.serviceInstances = LabelFilter.getLabelSelector().select($scope.unfilteredServiceInstances);
49+
};
50+
51+
var sortServiceInstances = function() {
52+
$scope.bindableServiceInstances = BindingService.filterBindableServiceInstances($scope.unfilteredServiceInstances, $scope.serviceClasses);
53+
$scope.unfilteredServiceInstances = BindingService.sortServiceInstances($scope.unfilteredServiceInstances, $scope.serviceClasses);
54+
};
55+
56+
/*var refreshSecrets = _.debounce(function(context) {
57+
DataService.list("secrets", context, null, { errorNotification: false }).then(function(secretData) {
58+
state.secrets = secretData.by("metadata.name");
59+
});
60+
}, 300);*/
61+
62+
var groupBindings = function() {
63+
// Build two maps:
64+
// - Bindings by the UID of the target object
65+
// - API objects by binding name
66+
/*
67+
state.bindingsByApplicationUID = {};
68+
state.applicationsByBinding = {};
69+
//state.deleteableBindingsByApplicationUID = {};
70+
71+
// If there are no bindings, nothing to do.
72+
if (_.isEmpty(state.bindings)) {
73+
return;
74+
}
75+
76+
// All objects that can be a target for bindings.
77+
var objectsByKind = [
78+
overview.deployments,
79+
overview.deploymentConfigs,
80+
overview.vanillaReplicationControllers,
81+
overview.vanillaReplicaSets,
82+
overview.statefulSets
83+
];
84+
85+
// Make sure all the binding targets have loaded first.
86+
if (_.some(objectsByKind, function(collection) { return !collection; })) {
87+
return;
88+
}
89+
90+
// Build a map of pod preset selectors by binding name.
91+
var podPresetSelectors = {};
92+
_.each(state.bindings, function(binding) {
93+
var podPresetSelector = _.get(binding, 'spec.alphaPodPresetTemplate.selector');
94+
if (podPresetSelector) {
95+
podPresetSelectors[binding.metadata.name] = new LabelSelector(podPresetSelector);
96+
}
97+
});
98+
99+
_.each(objectsByKind, function(collection) {
100+
_.each(collection, function(apiObject) {
101+
// Key by UID since name is not unique across different kinds.
102+
var applicationUID = getUID(apiObject);
103+
104+
// Create a selector for the potential binding target to check if the
105+
// pod preset covers the selector.
106+
var applicationSelector = new LabelSelector(_.get(apiObject, 'spec.selector'));
107+
state.bindingsByApplicationUID[applicationUID] = [];
108+
state.deleteableBindingsByApplicationUID[applicationUID] = [];
109+
110+
// Look at each pod preset selector to see if it covers this API object selector.
111+
_.each(podPresetSelectors, function(podPresetSelector, bindingName) {
112+
if (podPresetSelector.covers(applicationSelector)) {
113+
// Keep a map of the target UID to the binding and the binding to
114+
// the target. We want to show bindings both in the "application"
115+
// object rows and the service instance rows.
116+
state.bindingsByApplicationUID[applicationUID].push(state.bindings[bindingName]);
117+
if (!_.get(state.bindings[bindingName], 'metadata.deletionTimestamp')) {
118+
state.deleteableBindingsByApplicationUID[applicationUID].push(state.bindings[bindingName]);
119+
}
120+
state.applicationsByBinding[bindingName] = state.applicationsByBinding[bindingName] || [];
121+
state.applicationsByBinding[bindingName].push(apiObject);
122+
}
123+
});
124+
});
125+
});
126+
127+
$scope.bindingsByInstanceRef = _.reduce(state.bindingsByInstanceRef, function(result, bindingList, key) {
128+
result[key] = _.sortBy(bindingList, function(binding) {
129+
var apps = _.get(state.applicationsByBinding, [binding.metadata.name]);
130+
var firstName = _.get(_.head(apps), ['metadata', 'name']);
131+
return firstName || binding.metadata.name;
132+
});
133+
return result;
134+
}, {});*/
135+
};
136+
137+
ProjectsService
138+
.get($routeParams.project)
139+
.then(_.spread(function(project, context) {
140+
$scope.project = project;
141+
$scope.projectContext = context;
142+
143+
watches.push(DataService.watch({
144+
group: 'servicecatalog.k8s.io',
145+
resource: 'bindings'
146+
}, context, function(bindings) {
147+
$scope.bindings = bindings.by('metadata.name');
148+
$scope.bindingsByInstanceRef = _.groupBy($scope.bindings, 'spec.instanceRef.name');
149+
groupBindings();
150+
//refreshSecrets(context);
151+
}));
152+
153+
watches.push(DataService.watch({
154+
group: 'servicecatalog.k8s.io',
155+
resource: 'instances'
156+
}, context, function(serviceInstances) {
157+
$scope.emptyMessage = "No provisioned services to show";
158+
$scope.unfilteredServiceInstances = serviceInstances.by('metadata.name');
159+
160+
//_.each($scope.unfilteredServiceInstances, function (instance) {
161+
// var notifications = ResourceAlertsService.getServiceInstanceAlerts(instance);
162+
// setNotifications(instance, notifications);
163+
//});
164+
165+
sortServiceInstances();
166+
updateFilter();
167+
updateFilterWarning();
168+
169+
LabelFilter.addLabelSuggestionsFromResources($scope.unfilteredServiceInstances, $scope.labelSuggestions);
170+
LabelFilter.setLabelSuggestions($scope.labelSuggestions);
171+
172+
Logger.log("provisioned services (subscribe)", $scope.unfilteredServiceInstances);
173+
}));
174+
175+
DataService.list({
176+
group: 'servicecatalog.k8s.io',
177+
resource: 'serviceclasses'
178+
}, context, function(serviceClasses) {
179+
$scope.serviceClasses = serviceClasses.by('metadata.name');
180+
sortServiceInstances();
181+
updateFilter();
182+
});
183+
184+
function updateFilterWarning() {
185+
if (!LabelFilter.getLabelSelector().isEmpty() && _.isEmpty($scope.serviceInstances) && !_.isEmpty($scope.unfilteredServiceInstances)) {
186+
$scope.alerts["all-instances-filtered"] = {
187+
type: "warning",
188+
details: "The active filters are hiding all provisioned services."
189+
};
190+
}
191+
else {
192+
delete $scope.alerts["all-instances-filtered"];
193+
}
194+
}
195+
196+
LabelFilter.onActiveFiltersChanged(function(labelSelector) {
197+
// trigger a digest loop
198+
$scope.$apply(function() {
199+
$scope.serviceInstances = labelSelector.select($scope.unfilteredServiceInstances);
200+
updateFilterWarning();
201+
});
202+
});
203+
204+
$scope.$on('$destroy', function(){
205+
DataService.unwatchAll(watches);
206+
});
207+
208+
}));
209+
});

app/scripts/filters/canI.js

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ angular
2929
'imageStreams': [
3030
{group: '', resource: 'imagestreams', verbs: ['update', 'delete']}
3131
],
32+
'instances': [
33+
{group: 'servicecatalog.k8s.io', resource: 'instances', verbs: ['update', 'create', 'delete']}
34+
],
3235
'persistentVolumeClaims': [
3336
{group: '', resource: 'persistentvolumeclaims', verbs: ['update', 'delete']}
3437
],

app/scripts/services/navigate.js

+5
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ angular.module("openshiftConsole")
220220
.segmentCoded(name.substring(0, ind))
221221
.segmentCoded(name.substring(ind + 1));
222222
break;
223+
case "Instance":
224+
url.segment("service-instances")
225+
.segmentCoded(name);
226+
break;
223227
case "StatefulSet":
224228
url.segment("stateful-sets")
225229
.segmentCoded(name);
@@ -316,6 +320,7 @@ angular.module("openshiftConsole")
316320
'routes': 'routes',
317321
'secrets': 'secrets',
318322
'services': 'services',
323+
'service-instances': 'service-instances',
319324
'persistentvolumeclaims': 'storage',
320325
'statefulsets' : 'stateful-sets'
321326
};

0 commit comments

Comments
 (0)