diff --git a/magnum_ui/api/magnum.py b/magnum_ui/api/magnum.py index 15553d5e..c9639db5 100644 --- a/magnum_ui/api/magnum.py +++ b/magnum_ui/api/magnum.py @@ -181,3 +181,8 @@ def certificate_create(request, **kwargs): def certificate_show(request, id): return magnumclient(request).certificates.get(id) + + +def certificate_rotate(request, id): + args = {"cluster_uuid": id} + return magnumclient(request).certificates.rotate_ca(**args) diff --git a/magnum_ui/api/rest/magnum.py b/magnum_ui/api/rest/magnum.py index 8bfcd05c..791674d2 100644 --- a/magnum_ui/api/rest/magnum.py +++ b/magnum_ui/api/rest/magnum.py @@ -166,6 +166,14 @@ class Certificate(generic.View): ca = magnum.certificate_show(request, cluster_id) return ca.to_dict() + @rest_utils.ajax(data_required=True) + def delete(self, request, cluster_id): + """Rotate a certificate from a clsuter. + + Returns HTTP 204 (no content) on successful deletion. + """ + magnum.certificate_rotate(request, cluster_id) + @urls.register class Certificates(generic.View): diff --git a/magnum_ui/static/dashboard/container-infra/clusters/actions.module.js b/magnum_ui/static/dashboard/container-infra/clusters/actions.module.js index f91dcbb0..fa3dfb12 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/actions.module.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/actions.module.js @@ -37,6 +37,7 @@ 'horizon.dashboard.container-infra.clusters.update.service', 'horizon.dashboard.container-infra.clusters.show-certificate.service', 'horizon.dashboard.container-infra.clusters.sign-certificate.service', + 'horizon.dashboard.container-infra.clusters.rotate-certificate.service', 'horizon.dashboard.container-infra.clusters.resourceType' ]; @@ -48,6 +49,7 @@ updateClusterService, showCertificateService, signCertificateService, + rotateCertificateService, resourceType) { var clusterResourceType = registry.getResourceType(resourceType); @@ -86,6 +88,13 @@ text: gettext('Sign Certificate') } }) + .append({ + id: 'rotateCertificateAction', + service: rotateCertificateService, + template: { + text: gettext('Rotate Certificate') + } + }) .append({ id: 'updateClusterAction', service: updateClusterService, diff --git a/magnum_ui/static/dashboard/container-infra/clusters/actions.module.spec.js b/magnum_ui/static/dashboard/container-infra/clusters/actions.module.spec.js index 02cfebe9..04c0d726 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/actions.module.spec.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/actions.module.spec.js @@ -45,6 +45,11 @@ expect(actionHasId(actions, 'signCertificateAction')).toBe(true); }); + it('registers Rotate Certificate as an item action', function() { + var actions = registry.getResourceType('OS::Magnum::Cluster').itemActions; + expect(actionHasId(actions, 'rotateCertificateAction')).toBe(true); + }); + it('registers Delete Cluster as an item action', function() { var actions = registry.getResourceType('OS::Magnum::Cluster').itemActions; expect(actionHasId(actions, 'deleteClusterAction')).toBe(true); diff --git a/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.js b/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.js new file mode 100644 index 00000000..60ef61e7 --- /dev/null +++ b/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.js @@ -0,0 +1,76 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name horizon.dashboard.container-infra.clusters.rotate-certificate.service + * @description Service for the container-infra cluster rotate certificate + */ + angular + .module('horizon.dashboard.container-infra.clusters') + .factory( + 'horizon.dashboard.container-infra.clusters.rotate-certificate.service', + rotateCertificateService); + + rotateCertificateService.$inject = [ + 'horizon.app.core.openstack-service-api.magnum', + 'horizon.dashboard.container-infra.clusters.resourceType', + 'horizon.framework.util.actions.action-result.service', + 'horizon.framework.util.i18n.gettext', + 'horizon.framework.util.q.extensions', + 'horizon.framework.widgets.toast.service' + ]; + + function rotateCertificateService( + magnum, resourceType, actionResult, gettext, $qExtensions, toast + ) { + + var message = { + success: gettext('Certificate %s was successfully rotated.') + }; + + var service = { + initAction: initAction, + perform: perform, + allowed: allowed + }; + + return service; + + ////////////// + + function initAction() { + } + + function perform(selected) { + // rotate certificate + return magnum.rotateCertificate(selected.id).success(success); + } + + function success(response) { + response.data.id = response.data.uuid; + toast.add('success', interpolate(message.success, [response.data.id])); + var result = actionResult.getActionResult() + .deleted(resourceType, response.data.id); + return result.result; + } + + function allowed() { + return $qExtensions.booleanAsPromise(true); + } + } +})(); diff --git a/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.spec.js b/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.spec.js new file mode 100644 index 00000000..840f287f --- /dev/null +++ b/magnum_ui/static/dashboard/container-infra/clusters/rotate-certificate/rotate-certificate.service.spec.js @@ -0,0 +1,51 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +(function() { + 'use strict'; + + describe('horizon.dashboard.container-infra.clusters.rotate-certificate.service', function() { + + var service, selected, magnum; + + function fakePromise() { + return { success: angular.noop }; + } + + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.framework')); + beforeEach(module('horizon.dashboard.container-infra.clusters')); + + beforeEach(inject(function($injector) { + service = $injector.get( + 'horizon.dashboard.container-infra.clusters.rotate-certificate.service'); + magnum = $injector.get('horizon.app.core.openstack-service-api.magnum'); + spyOn(magnum, 'rotateCertificate').and.callFake(fakePromise); + })); + + it('should check the policy', function() { + var allowed = service.allowed(); + expect(allowed).toBeTruthy(); + }); + + it('should get magnum.rotatecertificate', function() { + selected = { + id: '1' + }; + service.initAction(); + service.perform(selected); + expect(magnum.rotateCertificate).toHaveBeenCalled(); + }); + }); +})(); diff --git a/magnum_ui/static/dashboard/container-infra/magnum.service.js b/magnum_ui/static/dashboard/container-infra/magnum.service.js index 4785e2fc..cd3c95d8 100644 --- a/magnum_ui/static/dashboard/container-infra/magnum.service.js +++ b/magnum_ui/static/dashboard/container-infra/magnum.service.js @@ -43,6 +43,7 @@ deleteClusterTemplates: deleteClusterTemplates, showCertificate: showCertificate, signCertificate: signCertificate, + rotateCertificate: rotateCertificate, downloadTextAsFile: downloadTextAsFile, getNetworks: getNetworks }; @@ -163,6 +164,13 @@ }); } + function rotateCertificate(id) { + return apiService.delete('/api/container_infra/certificates/' + id, [id]) + .error(function() { + toastService.add('error', gettext('Unable to rotate the certificate.')); + }); + } + function downloadTextAsFile(text, filename) { // create text file as object url var blob = new Blob([ text ], { "type" : "text/plain" }); diff --git a/magnum_ui/static/dashboard/container-infra/magnum.service.spec.js b/magnum_ui/static/dashboard/container-infra/magnum.service.spec.js index 44d07b2f..b9b45447 100644 --- a/magnum_ui/static/dashboard/container-infra/magnum.service.spec.js +++ b/magnum_ui/static/dashboard/container-infra/magnum.service.spec.js @@ -152,6 +152,14 @@ "path": "/api/container_infra/certificates/123", "error": "Unable to retrieve the certificate.", "testInput": [123] + }, + { + "func": "rotateCertificate", + "method": "delete", + "path": "/api/container_infra/certificates/123", + "data": [123], + "error": "Unable to rotate the certificate.", + "testInput": [123, [123]] } ];