From 051b3cbd1e014e931c4568b048535774aea0547f Mon Sep 17 00:00:00 2001 From: Justin Pomeroy Date: Fri, 4 Mar 2016 10:39:09 -0600 Subject: [PATCH] Add edit health monitor action This adds the action to update a health monitor. Partially-Implements: blueprint horizon-lbaas-v2-ui Change-Id: I017c7adc885a02420e47b0dfff7c314054f189b0 --- neutron_lbaas_dashboard/api/rest/lbaasv2.py | 7 ++ .../openstack-service-api/lbaasv2.service.js | 20 +++- .../lbaasv2.service.spec.js | 8 ++ .../actions/edit/edit.action.service.js | 80 +++++++++++++++ .../actions/edit/edit.action.service.spec.js | 98 +++++++++++++++++++ .../actions/edit/wizard.controller.js | 42 ++++++++ .../actions/edit/wizard.controller.spec.js | 63 ++++++++++++ .../actions/row-actions.service.js | 9 +- .../actions/row-actions.service.spec.js | 5 +- .../project/lbaasv2/workflow/model.service.js | 16 ++- .../lbaasv2/workflow/model.service.spec.js | 76 ++++++++++++++ 11 files changed, 419 insertions(+), 5 deletions(-) create mode 100644 neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js create mode 100644 neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js create mode 100644 neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js create mode 100644 neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js diff --git a/neutron_lbaas_dashboard/api/rest/lbaasv2.py b/neutron_lbaas_dashboard/api/rest/lbaasv2.py index 0e39ce8f..2b900268 100644 --- a/neutron_lbaas_dashboard/api/rest/lbaasv2.py +++ b/neutron_lbaas_dashboard/api/rest/lbaasv2.py @@ -710,3 +710,10 @@ class HealthMonitor(generic.View): http://localhost/api/lbaas/healthmonitors/cc758c90-3d98-4ea1-af44-aab405c9c915 """ neutronclient(request).delete_lbaas_healthmonitor(healthmonitor_id) + + @rest_utils.ajax() + def put(self, request, healthmonitor_id): + """Edit a health monitor. + + """ + update_monitor(request) diff --git a/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js b/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js index 1667df58..bea7da23 100644 --- a/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js +++ b/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js @@ -54,7 +54,8 @@ getMember: getMember, getHealthMonitor: getHealthMonitor, deleteHealthMonitor: deleteHealthMonitor, - createHealthMonitor: createHealthMonitor + createHealthMonitor: createHealthMonitor, + editHealthMonitor: editHealthMonitor }; return service; @@ -360,6 +361,23 @@ }); } + /** + * @name horizon.app.core.openstack-service-api.lbaasv2.editHealthMonitor + * @description + * Edit a health monitor + * @param {string} id + * Specifies the id of the health monitor to update. + * @param {object} spec + * Specifies the data used to update the health monitor. + */ + + function editHealthMonitor(id, spec) { + return apiService.put('/api/lbaas/healthmonitors/' + id, spec) + .error(function () { + toastService.add('error', gettext('Unable to update health monitor.')); + }); + } + /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteHealthMonitor * @description diff --git a/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js b/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js index 9060f3fb..27fa898c 100644 --- a/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js +++ b/neutron_lbaas_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js @@ -134,6 +134,14 @@ error: 'Unable to retrieve health monitor.', testInput: [ '1234' ] }, + { + func: 'editHealthMonitor', + method: 'put', + path: '/api/lbaas/healthmonitors/1234', + error: 'Unable to update health monitor.', + data: { name: 'healthmonitor-1' }, + testInput: [ '1234', { name: 'healthmonitor-1' } ] + }, { func: 'deleteHealthMonitor', method: 'delete', diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js new file mode 100644 index 00000000..baf61537 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js @@ -0,0 +1,80 @@ +/* + * Copyright 2016 IBM Corp. + * + * 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'; + + angular + .module('horizon.dashboard.project.lbaasv2.healthmonitors') + .factory('horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit', editService); + + editService.$inject = [ + '$q', + '$route', + 'horizon.dashboard.project.lbaasv2.workflow.modal', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.framework.util.i18n.gettext' + ]; + + /** + * @ngDoc factory + * @name horizon.dashboard.project.lbaasv2.healthmonitors.actions.editService + * @description + * Provides the service for editing a health monitor resource. + * @param $q The angular service for promises. + * @param $route The angular $route service. + * @param workflowModal The LBaaS workflow modal service. + * @param policy The horizon policy service. + * @param gettext The horizon gettext function for translation. + * @returns The health monitor edit service. + */ + + function editService($q, $route, workflowModal, policy, gettext) { + var statePromise; + + var edit = workflowModal.init({ + controller: 'EditHealthMonitorWizardController', + message: gettext('The health monitor has been updated.'), + handle: handle, + allowed: allowed + }); + + var service = { + init: init, + edit: edit + }; + + return service; + + ////////////// + + function init(_statePromise_) { + statePromise = _statePromise_; + return service; + } + + function allowed(/*healthmonitor*/) { + return $q.all([ + statePromise, + policy.ifAllowed({ rules: [['neutron', 'update_health_monitor']] }) + ]); + } + + function handle(/*response*/) { + $route.reload(); + } + + } +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js new file mode 100644 index 00000000..e08ee9dd --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js @@ -0,0 +1,98 @@ +/* + * Copyright 2016 IBM Corp. + * + * 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('LBaaS v2 Edit Health Monitor Action Service', function() { + var scope, $q, $route, policy, init, service, loadBalancerState; + + function allowed(item) { + spyOn(policy, 'ifAllowed').and.returnValue(true); + var promise = service.edit.allowed(item); + var allowed; + promise.then(function() { + allowed = true; + }, function() { + allowed = false; + }); + scope.$apply(); + expect(policy.ifAllowed).toHaveBeenCalledWith( + {rules: [['neutron', 'update_health_monitor']]}); + return allowed; + } + + beforeEach(module('horizon.framework.util')); + beforeEach(module('horizon.framework.conf')); + beforeEach(module('horizon.framework.widgets')); + beforeEach(module('horizon.app.core.openstack-service-api')); + beforeEach(module('horizon.dashboard.project.lbaasv2')); + + beforeEach(module(function($provide) { + $provide.value('$modal', { + open: function() { + return { + result: { + then: function(func) { + func({ data: { id: 'healthmonitor1' } }); + } + } + }; + } + }); + })); + + beforeEach(inject(function ($injector) { + scope = $injector.get('$rootScope').$new(); + $q = $injector.get('$q'); + policy = $injector.get('horizon.app.core.openstack-service-api.policy'); + $route = $injector.get('$route'); + service = $injector.get('horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit'); + init = service.init; + loadBalancerState = $q.defer(); + })); + + it('should define the correct service properties', function() { + expect(service.init).toBeDefined(); + expect(service.edit).toBeDefined(); + }); + + it('should have the "allowed" and "perform" functions', function() { + expect(service.edit.allowed).toBeDefined(); + expect(service.edit.perform).toBeDefined(); + }); + + it('should allow edit a health monitor under an ACTIVE load balancer', function() { + loadBalancerState.resolve(); + init(loadBalancerState.promise); + expect(allowed({})).toBe(true); + }); + + it('should not allow editing a health monitor under a NON-ACTIVE load balancer', function() { + loadBalancerState.reject(); + init(loadBalancerState.promise); + expect(allowed({})).toBe(false); + }); + + it('should reload page after edit', function() { + loadBalancerState.resolve(); + spyOn($route, 'reload'); + init(loadBalancerState.promise).edit.allowed({}); + service.edit.perform(); + expect($route.reload).toHaveBeenCalled(); + }); + + }); +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js new file mode 100644 index 00000000..cd1b414a --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js @@ -0,0 +1,42 @@ +/* + * Copyright 2016 IBM Corp. + * + * 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'; + + angular + .module('horizon.dashboard.project.lbaasv2.healthmonitors') + .controller('EditHealthMonitorWizardController', EditHealthMonitorWizardController); + + EditHealthMonitorWizardController.$inject = [ + '$scope', + 'horizon.dashboard.project.lbaasv2.workflow.model', + 'horizon.dashboard.project.lbaasv2.workflow.workflow', + 'horizon.framework.util.i18n.gettext' + ]; + + function EditHealthMonitorWizardController($scope, model, workflowService, gettext) { + var scope = $scope; + scope.model = model; + scope.submit = scope.model.submit; + scope.workflow = workflowService( + gettext('Update Health Monitor'), + 'fa fa-cloud-download', + ['monitor'] + ); + scope.model.initialize('monitor', scope.launchContext.id); + } + +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js new file mode 100644 index 00000000..627df8c1 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js @@ -0,0 +1,63 @@ +/* + * Copyright 2016 IBM Corp. + * + * 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('LBaaS v2 Edit Health Monitor Wizard Controller', function() { + var ctrl; + var model = { + submit: function() { + return 'updated'; + }, + initialize: angular.noop + }; + var workflow = function() { + return 'foo'; + }; + var scope = { + launchContext: {id: 'healthmonitor1'} + }; + + beforeEach(module('horizon.framework.util')); + beforeEach(module('horizon.dashboard.project.lbaasv2')); + beforeEach(module(function ($provide) { + $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); + $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); + })); + beforeEach(inject(function ($controller) { + spyOn(model, 'initialize'); + ctrl = $controller('EditHealthMonitorWizardController', { $scope: scope }); + })); + + it('defines the controller', function() { + expect(ctrl).toBeDefined(); + }); + + it('calls initialize on the given model', function() { + expect(model.initialize).toHaveBeenCalled(); + }); + + it('sets scope.workflow to the given workflow', function() { + expect(scope.workflow).toBe('foo'); + }); + + it('defines scope.submit', function() { + expect(scope.submit).toBeDefined(); + expect(scope.submit()).toBe('updated'); + }); + }); + +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.js index fffa5565..9bc4394a 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.js @@ -24,6 +24,7 @@ rowActions.$inject = [ 'horizon.framework.util.i18n.gettext', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', + 'horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit', 'horizon.dashboard.project.lbaasv2.healthmonitors.actions.delete' ]; @@ -36,11 +37,12 @@ * * @param gettext The horizon gettext function for translation. * @param loadBalancersService The LBaaS v2 load balancers service. + * @param editService The LBaaS v2 health monitor edit service. * @param deleteService The LBaaS v2 health monitor delete service. * @returns Health monitor row actions service object. */ - function rowActions(gettext, loadBalancersService, deleteService) { + function rowActions(gettext, loadBalancersService, editService, deleteService) { var loadBalancerIsActionable, loadbalancerId, listenerId, poolId; var service = { @@ -62,6 +64,11 @@ function actions() { return [{ + service: editService.init(loadBalancerIsActionable).edit, + template: { + text: gettext('Edit') + } + },{ service: deleteService.init(loadbalancerId, listenerId, poolId, loadBalancerIsActionable), template: { text: gettext('Delete Health Monitor'), diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.spec.js index 7ac9ed9b..31abe592 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.spec.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/row-actions.service.spec.js @@ -35,8 +35,9 @@ })); it('should define correct table row actions', function() { - expect(actions.length).toBe(1); - expect(actions[0].template.text).toBe('Delete Health Monitor'); + expect(actions.length).toBe(2); + expect(actions[0].template.text).toBe('Edit'); + expect(actions[1].template.text).toBe('Delete Health Monitor'); }); it('should have the "allowed" and "perform" functions', function() { diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js index ddf1652e..351d379a 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js @@ -190,7 +190,8 @@ 'createmonitor': initCreateMonitor, 'editloadbalancer': initEditLoadBalancer, 'editlistener': initEditListener, - 'editpool': initEditPool + 'editpool': initEditPool, + 'editmonitor': initEditMonitor }[type](keymanagerPromise); return promise.then(onInitSuccess, onInitFail); @@ -271,6 +272,11 @@ ]).then(initMemberAddresses); } + function initEditMonitor() { + model.context.submit = editHealthMonitor; + return lbaasv2API.getHealthMonitor(model.context.id).then(onGetHealthMonitor); + } + /** * @ngdoc method * @name workflowModel.submit @@ -321,6 +327,10 @@ return lbaasv2API.editPool(model.context.id, spec); } + function editHealthMonitor(spec) { + return lbaasv2API.editHealthMonitor(model.context.id, spec); + } + function cleanFinalSpecLoadBalancer(finalSpec) { var context = model.context; @@ -631,6 +641,10 @@ spec.path = monitor.url_path; } + function onGetHealthMonitor(response) { + setMonitorSpec(response.data); + } + function prepareCertificates() { return $q.all([ barbicanAPI.getCertificates(true), diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js index 74f8c623..c3fc406c 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js @@ -185,6 +185,9 @@ }, createHealthMonitor: function(spec) { return spec; + }, + editHealthMonitor: function(id, spec) { + return spec; } }); @@ -568,6 +571,42 @@ }); }); + describe('Post initialize model (edit health monitor)', function() { + + beforeEach(function() { + model.initialize('monitor', 'healthmonitor1'); + scope.$apply(); + }); + + it('should initialize model properties', function() { + expect(model.initializing).toBe(false); + expect(model.initialized).toBe(true); + expect(model.subnets.length).toBe(0); + expect(model.members.length).toBe(0); + expect(model.certificates.length).toBe(0); + expect(model.listenerPorts.length).toBe(0); + expect(model.spec.loadbalancer_id).toBeUndefined(); + expect(model.spec.parentResourceId).toBeUndefined(); + expect(model.spec.members.length).toBe(0); + expect(model.spec.certificates).toEqual([]); + expect(model.certificatesError).toBe(false); + expect(model.spec.monitor.id).toBe('1234'); + expect(model.spec.monitor.type).toBe('HTTP'); + expect(model.spec.monitor.interval).toBe(1); + expect(model.spec.monitor.timeout).toBe(1); + expect(model.spec.monitor.retry).toBe(1); + expect(model.spec.monitor.method).toBe('POST'); + expect(model.spec.monitor.status).toBe('200'); + expect(model.spec.monitor.path).toBe('/test'); + }); + + it('should initialize context properties', function() { + expect(model.context.resource).toBe('monitor'); + expect(model.context.id).toBe('healthmonitor1'); + expect(model.context.submit.name).toBe('editHealthMonitor'); + }); + }); + describe('Post initialize model (without barbican)', function() { beforeEach(function() { @@ -1730,6 +1769,7 @@ }); it('should set final spec properties', function() { + var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeUndefined(); @@ -1803,6 +1843,42 @@ }); }); + describe('Model submit function (edit health monitor)', function() { + + beforeEach(function() { + model.initialize('monitor', 'healthmonitor1'); + scope.$apply(); + }); + + it('should set final spec properties', function() { + model.spec.monitor.interval = 10; + model.spec.monitor.retry = 6; + model.spec.monitor.timeout = 8; + model.spec.monitor.method = 'GET'; + model.spec.monitor.status = '200-204'; + model.spec.monitor.path = '/foo/bar'; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer_id).toBeUndefined(); + expect(finalSpec.parentResourceId).toBeUndefined(); + expect(finalSpec.loadbalancer).toBeUndefined(); + expect(finalSpec.listener).toBeUndefined(); + expect(finalSpec.pool).toBeUndefined(); + expect(finalSpec.members).toBeUndefined(); + expect(finalSpec.certificates).toBeUndefined(); + + expect(finalSpec.monitor.type).toBe('HTTP'); + expect(finalSpec.monitor.interval).toBe(10); + expect(finalSpec.monitor.retry).toBe(6); + expect(finalSpec.monitor.timeout).toBe(8); + expect(finalSpec.monitor.method).toBe('GET'); + expect(finalSpec.monitor.status).toBe('200-204'); + expect(finalSpec.monitor.path).toBe('/foo/bar'); + }); + + }); + describe('Model visible resources (edit listener, no pool)', function() { beforeEach(function() {