Skip to content

Commit b5dcf95

Browse files
Do not attempt service instance deletion if it has bindings
Fixes #2149
1 parent 1dae20b commit b5dcf95

File tree

6 files changed

+207
-75
lines changed

6 files changed

+207
-75
lines changed

app/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ <h1>JavaScript Required</h1>
298298
<script src="scripts/controllers/modals/linkService.js"></script>
299299
<script src="scripts/controllers/modals/jenkinsfileExamplesModal.js"></script>
300300
<script src="scripts/controllers/modals/aboutComputeUnitsModal.js"></script>
301+
<script src="scripts/controllers/modals/warningModal.js"></script>
301302
<script src="scripts/controllers/about.js"></script>
302303
<script src="scripts/controllers/commandLine.js"></script>
303304
<script src="scripts/controllers/createPersistentVolumeClaim.js"></script>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
/* jshint unused: false */
3+
4+
/**
5+
* @ngdoc function
6+
* @name openshiftConsole.controller:WarningModalController
7+
* @description
8+
* # WarningModalController
9+
* Controller of the openshiftConsole
10+
*/
11+
angular.module('openshiftConsole')
12+
.controller('WarningModalController', function($scope,
13+
$uibModalInstance,
14+
modalConfig) {
15+
// content supplied in the following forms:
16+
// heading: modalConfig.title
17+
// content: strongMessage (strong text)
18+
// content: modalConfig.message (plain text ONLY, no user input)
19+
// content: modalConfig.messageMarkup (pre-sanitized, see _.escape() or _.template('<%- %>') )
20+
// button: closeButtonText
21+
_.extend($scope, modalConfig);
22+
23+
$scope.close = function() {
24+
$uibModalInstance.dismiss('cancel');
25+
};
26+
});

app/scripts/services/serviceInstances.js

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,105 @@
33
angular.module("openshiftConsole")
44
.factory("ServiceInstancesService", function($filter,
55
$uibModal,
6+
BindingService,
7+
CatalogService,
68
DataService,
79
NotificationsService) {
8-
9-
function deprovision(apiObject) {
10+
var doDeprovision = function (apiObject) {
1011
var getErrorDetails = $filter('getErrorDetails');
12+
var modalInstance;
13+
1114
var modalScope = {
12-
alerts: {
13-
deprovision: {
14-
type: 'error',
15-
message: 'Service \'' + apiObject.spec.serviceClassName + '\' will be deleted and no longer available.'
16-
}
17-
},
18-
detailsMarkup: 'Delete Service?',
15+
kind: apiObject.kind,
16+
displayName: apiObject.metadata.name,
1917
okButtonText: 'Delete',
2018
okButtonClass: 'btn-danger',
21-
cancelButtonText: 'Cancel'
19+
cancelButtonText: 'Cancel',
20+
delete: function() {
21+
modalInstance.close('delete');
22+
}
2223
};
2324

24-
// TODO: we probably have to handle bindings in here.
25-
// either:
26-
// - automatically remove the bindings
27-
// - tell the user they must manually unbind before continue
28-
return $uibModal.open({
25+
modalInstance = $uibModal.open({
2926
animation: true,
30-
templateUrl: 'views/modals/confirm.html',
27+
templateUrl: 'views/modals/delete-resource.html',
3128
controller: 'ConfirmModalController',
3229
resolve: {
3330
modalConfig: function() {
3431
return modalScope;
3532
}
3633
}
37-
})
38-
.result.then(function() {
34+
});
35+
36+
return modalInstance.result.then(function() {
3937
NotificationsService.hideNotification("deprovision-service-error");
4038

41-
return DataService.delete({
42-
group: 'servicecatalog.k8s.io',
43-
resource: 'serviceinstances'
44-
},
45-
apiObject.metadata.name,
46-
{ namespace: apiObject.metadata.namespace },
47-
{ propagationPolicy: null
48-
}) // TODO - remove once this is resolved https://github.com/kubernetes-incubator/service-catalog/issues/942
49-
.then(function() {
50-
NotificationsService.addNotification({
51-
type: "success",
52-
message: "Successfully deleted provisioned service " + apiObject.metadata.name + "."
53-
});
54-
}, function(err) {
55-
NotificationsService.addNotification({
56-
id: "deprovision-service-error",
57-
type: "error",
58-
message: "An error occurred while deleting provisioned service " + apiObject.metadata.name + ".",
59-
details: getErrorDetails(err)
60-
});
39+
var context = {namespace: apiObject.metadata.namespace};
40+
var resource = {
41+
group: 'servicecatalog.k8s.io',
42+
resource: 'serviceinstances'
43+
};
44+
45+
// TODO - remove once this is resolved https://github.com/kubernetes-incubator/service-catalog/issues/942
46+
var opts = {
47+
propagationPolicy: null
48+
};
49+
50+
return DataService.delete(resource, apiObject.metadata.name, context, opts).then(function() {
51+
NotificationsService.addNotification({
52+
type: "success",
53+
message: "Successfully deleted provisioned service " + apiObject.metadata.name + "."
54+
});
55+
}, function(err) {
56+
NotificationsService.addNotification({
57+
id: "deprovision-service-error",
58+
type: "error",
59+
message: "An error occurred while deleting provisioned service " + apiObject.metadata.name + ".",
60+
details: getErrorDetails(err)
6161
});
62+
});
6263
});
63-
}
64+
};
65+
66+
var showUnableToDeprovisionDialog = function() {
67+
return $uibModal.open({
68+
animation: true,
69+
templateUrl: 'views/modals/warning.html',
70+
controller: 'WarningModalController',
71+
resolve: {
72+
modalConfig: function() {
73+
return {
74+
title: "Unable to Deprovision",
75+
strongMessage: "This service cannot be deprovisioned because it has bindings.",
76+
message: "You must delete all bindings from the service before you can deprovision it."
77+
};
78+
}
79+
}
80+
});
81+
};
82+
83+
var deprovision = function (apiObject) {
84+
var context = {namespace: apiObject.metadata.namespace};
85+
var resource = {
86+
group: 'servicecatalog.k8s.io',
87+
resource: 'serviceinstancecredentials'
88+
};
89+
90+
if (CatalogService.SERVICE_CATALOG_ENABLED) {
91+
DataService.list(resource, context, function (bindings) {
92+
var serviceBindings = BindingService.getBindingsForResource(bindings.by('metadata.name'), apiObject);
93+
if (serviceBindings.length > 0) {
94+
showUnableToDeprovisionDialog();
95+
} else {
96+
doDeprovision(apiObject);
97+
}
98+
}, function() {
99+
doDeprovision(apiObject);
100+
});
101+
} else {
102+
doDeprovision(apiObject);
103+
}
104+
};
64105

65106
return {
66107
deprovision: deprovision

app/views/modals/warning.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<div class="modal-resource-action">
2+
<div class="modal-body">
3+
<h1>
4+
<span class="pficon pficon-warning-triangle-o"></span>
5+
{{title}}
6+
</h1>
7+
<p class="strong" ng-if="strongMessage">{{strongMessage}}</p>
8+
<p ng-if="message">{{message}}</p>
9+
<p ng-if="messageMarkup" ng-bind-html="messageMarkup"></p>
10+
</div>
11+
<div class="modal-footer">
12+
<button class="btn btn-lg btn-default" type="button" ng-click="close()">{{closeButtonText || 'Close'}}</button>
13+
</div>
14+
</div>

dist/scripts/scripts.js

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ return _.get(e, "metadata.name");
5353
return _.get(e, "metadata.uid");
5454
}, G = function() {
5555
return _.size(P.deploymentConfigs) + _.size(P.vanillaReplicationControllers) + _.size(P.deployments) + _.size(P.vanillaReplicaSets) + _.size(P.statefulSets) + _.size(P.monopods) + _.size(P.state.serviceInstances);
56-
}, K = function() {
57-
return _.size(P.filteredDeploymentConfigs) + _.size(P.filteredReplicationControllers) + _.size(P.filteredDeployments) + _.size(P.filteredReplicaSets) + _.size(P.filteredStatefulSets) + _.size(P.filteredMonopods) + _.size(P.filteredServiceInstances);
5856
}, W = function() {
59-
P.size = G(), P.filteredSize = K();
57+
return _.size(P.filteredDeploymentConfigs) + _.size(P.filteredReplicationControllers) + _.size(P.filteredDeployments) + _.size(P.filteredReplicaSets) + _.size(P.filteredStatefulSets) + _.size(P.filteredMonopods) + _.size(P.filteredServiceInstances);
58+
}, K = function() {
59+
P.size = G(), P.filteredSize = W();
6060
var e = 0 === P.size, t = P.deploymentConfigs && P.replicationControllers && P.deployments && P.replicaSets && P.statefulSets && P.pods && P.state.serviceInstances;
6161
V.expandAll = t && 1 === P.size, P.showGetStarted = t && e, P.showLoading = !t && e, P.everythingFiltered = !e && !P.filteredSize, P.hidePipelineOtherResources = "pipeline" === P.viewBy && (P.filterActive || _.isEmpty(P.pipelineBuildConfigs));
6262
}, Q = function(e) {
@@ -119,7 +119,7 @@ case "name":
119119
return !_.isEmpty(V.filterKeywords);
120120
}
121121
}, ie = function() {
122-
P.filteredDeploymentConfigs = re(P.deploymentConfigs), P.filteredReplicationControllers = re(P.vanillaReplicationControllers), P.filteredDeployments = re(P.deployments), P.filteredReplicaSets = re(P.vanillaReplicaSets), P.filteredStatefulSets = re(P.statefulSets), P.filteredMonopods = re(P.monopods), P.filteredPipelineBuildConfigs = re(P.pipelineBuildConfigs), P.filteredServiceInstances = re(V.orderedServiceInstances), P.filterActive = oe(), Z(), W();
122+
P.filteredDeploymentConfigs = re(P.deploymentConfigs), P.filteredReplicationControllers = re(P.vanillaReplicationControllers), P.filteredDeployments = re(P.deployments), P.filteredReplicaSets = re(P.vanillaReplicaSets), P.filteredStatefulSets = re(P.statefulSets), P.filteredMonopods = re(P.monopods), P.filteredPipelineBuildConfigs = re(P.pipelineBuildConfigs), P.filteredServiceInstances = re(V.orderedServiceInstances), P.filterActive = oe(), Z(), K();
123123
}, se = n.project + "/overview/view-by";
124124
P.viewBy = localStorage.getItem(se) || "app", e.$watch(function() {
125125
return P.viewBy;
@@ -315,7 +315,7 @@ _.isEmpty(o) || (t = t.concat(o));
315315
qe(), ze();
316316
}, Ge = function() {
317317
_.each(P.deploymentConfigs, Me);
318-
}, Ke = function() {
318+
}, We = function() {
319319
if (V.builds && P.buildConfigs) {
320320
P.recentPipelinesByBuildConfig = {}, V.recentBuildsByBuildConfig = {}, V.recentPipelinesByDeploymentConfig = {};
321321
var e = {};
@@ -330,7 +330,7 @@ return i.sortBuilds(e, !0);
330330
return i.sortBuilds(e, !0);
331331
}), Ge();
332332
}
333-
}, We = function() {
333+
}, Ke = function() {
334334
k.setQuotaNotifications(V.quotas, V.clusterQuotas, n.project);
335335
};
336336
P.clearFilter = function() {
@@ -395,7 +395,7 @@ resource: "deployments"
395395
}, a, function(e) {
396396
I = e.by("metadata.uid"), P.deployments = _.sortBy(I, "metadata.name"), Ee(), Ae(P.deployments), Ae(P.vanillaReplicaSets), we(P.deployments), Qe(), ie(), h.log("deployments (subscribe)", P.deploymentsByUID);
397397
})), Ye.push(l.watch("builds", a, function(e) {
398-
V.builds = e.by("metadata.name"), Ke(), h.log("builds (subscribe)", V.builds);
398+
V.builds = e.by("metadata.name"), We(), h.log("builds (subscribe)", V.builds);
399399
})), Ye.push(l.watch({
400400
group: "apps",
401401
resource: "statefulsets"
@@ -415,7 +415,7 @@ P.routes = e.by("metadata.name"), Be(), h.log("routes (subscribe)", P.routes);
415415
poll: R,
416416
pollInterval: 6e4
417417
})), Ye.push(l.watch("buildConfigs", a, function(e) {
418-
P.buildConfigs = e.by("metadata.name"), Fe(), He(), Ke(), ie(), h.log("buildconfigs (subscribe)", P.buildConfigs);
418+
P.buildConfigs = e.by("metadata.name"), Fe(), He(), We(), ie(), h.log("buildconfigs (subscribe)", P.buildConfigs);
419419
}, {
420420
poll: R,
421421
pollInterval: 6e4
@@ -434,12 +434,12 @@ T = e.by("metadata.name"), m.buildDockerRefMapForImageStreams(T, V.imageStreamIm
434434
poll: R,
435435
pollInterval: 6e4
436436
})), Ye.push(l.watch("resourcequotas", a, function(e) {
437-
V.quotas = e.by("metadata.name"), We();
437+
V.quotas = e.by("metadata.name"), Ke();
438438
}, {
439439
poll: !0,
440440
pollInterval: 6e4
441441
})), Ye.push(l.watch("appliedclusterresourcequotas", a, function(e) {
442-
V.clusterQuotas = e.by("metadata.name"), We();
442+
V.clusterQuotas = e.by("metadata.name"), Ke();
443443
}, {
444444
poll: !0,
445445
pollInterval: 6e4
@@ -4277,52 +4277,80 @@ controller: !0
42774277
});
42784278
}
42794279
};
4280-
}), angular.module("openshiftConsole").factory("ServiceInstancesService", [ "$filter", "$uibModal", "DataService", "NotificationsService", function(e, t, n, a) {
4281-
return {
4282-
deprovision: function(r) {
4283-
var o = e("getErrorDetails"), i = {
4284-
alerts: {
4285-
deprovision: {
4286-
type: "error",
4287-
message: "Service '" + r.spec.serviceClassName + "' will be deleted and no longer available."
4288-
}
4289-
},
4290-
detailsMarkup: "Delete Service?",
4280+
}), angular.module("openshiftConsole").factory("ServiceInstancesService", [ "$filter", "$uibModal", "BindingService", "CatalogService", "DataService", "NotificationsService", function(e, t, n, a, r, o) {
4281+
var i = function(n) {
4282+
var a, i = e("getErrorDetails"), s = {
4283+
kind: n.kind,
4284+
displayName: n.metadata.name,
42914285
okButtonText: "Delete",
42924286
okButtonClass: "btn-danger",
4293-
cancelButtonText: "Cancel"
4287+
cancelButtonText: "Cancel",
4288+
delete: function() {
4289+
a.close("delete");
4290+
}
42944291
};
4295-
return t.open({
4292+
return (a = t.open({
42964293
animation: !0,
4297-
templateUrl: "views/modals/confirm.html",
4294+
templateUrl: "views/modals/delete-resource.html",
42984295
controller: "ConfirmModalController",
42994296
resolve: {
43004297
modalConfig: function() {
4301-
return i;
4298+
return s;
43024299
}
43034300
}
4304-
}).result.then(function() {
4305-
return a.hideNotification("deprovision-service-error"), n.delete({
4301+
})).result.then(function() {
4302+
o.hideNotification("deprovision-service-error");
4303+
var e = {
4304+
namespace: n.metadata.namespace
4305+
}, t = {
43064306
group: "servicecatalog.k8s.io",
43074307
resource: "serviceinstances"
4308-
}, r.metadata.name, {
4309-
namespace: r.metadata.namespace
4310-
}, {
4308+
}, a = {
43114309
propagationPolicy: null
4312-
}).then(function() {
4313-
a.addNotification({
4310+
};
4311+
return r.delete(t, n.metadata.name, e, a).then(function() {
4312+
o.addNotification({
43144313
type: "success",
4315-
message: "Successfully deleted provisioned service " + r.metadata.name + "."
4314+
message: "Successfully deleted provisioned service " + n.metadata.name + "."
43164315
});
43174316
}, function(e) {
4318-
a.addNotification({
4317+
o.addNotification({
43194318
id: "deprovision-service-error",
43204319
type: "error",
4321-
message: "An error occurred while deleting provisioned service " + r.metadata.name + ".",
4322-
details: o(e)
4320+
message: "An error occurred while deleting provisioned service " + n.metadata.name + ".",
4321+
details: i(e)
43234322
});
43244323
});
43254324
});
4325+
}, s = function() {
4326+
return t.open({
4327+
animation: !0,
4328+
templateUrl: "views/modals/warning.html",
4329+
controller: "WarningModalController",
4330+
resolve: {
4331+
modalConfig: function() {
4332+
return {
4333+
title: "Unable to Deprovision",
4334+
strongMessage: "This service cannot be deprovisioned because it has bindings.",
4335+
message: "You must delete all bindings from the service before you can deprovision it."
4336+
};
4337+
}
4338+
}
4339+
});
4340+
};
4341+
return {
4342+
deprovision: function(e) {
4343+
var t = {
4344+
namespace: e.metadata.namespace
4345+
}, o = {
4346+
group: "servicecatalog.k8s.io",
4347+
resource: "serviceinstancecredentials"
4348+
};
4349+
a.SERVICE_CATALOG_ENABLED ? r.list(o, t, function(t) {
4350+
n.getBindingsForResource(t.by("metadata.name"), e).length > 0 ? s() : i(e);
4351+
}, function() {
4352+
i(e);
4353+
}) : i(e);
43264354
}
43274355
};
43284356
} ]), angular.module("openshiftConsole").controller("LandingPageController", [ "$scope", "$rootScope", "AuthService", "Catalog", "Constants", "DataService", "Navigate", "NotificationsService", "RecentlyViewedServiceItems", "GuidedTourService", "HTMLService", "$timeout", "$q", "$routeParams", "$location", function(e, t, n, a, r, o, i, s, c, l, u, d, p, m, f) {
@@ -8666,6 +8694,10 @@ t.close("ok");
86668694
e.ok = function() {
86678695
t.close("ok");
86688696
};
8697+
} ]), angular.module("openshiftConsole").controller("WarningModalController", [ "$scope", "$uibModalInstance", "modalConfig", function(e, t, n) {
8698+
_.extend(e, n), e.close = function() {
8699+
t.dismiss("cancel");
8700+
};
86698701
} ]), angular.module("openshiftConsole").controller("AboutController", [ "$scope", "AuthService", "Constants", function(e, t, n) {
86708702
t.withUser(), e.version = {
86718703
master: {

0 commit comments

Comments
 (0)