diff --git a/neutron_lbaas_dashboard/api/rest/lbaasv2.py b/neutron_lbaas_dashboard/api/rest/lbaasv2.py index ffe3a0fa..86059a07 100644 --- a/neutron_lbaas_dashboard/api/rest/lbaasv2.py +++ b/neutron_lbaas_dashboard/api/rest/lbaasv2.py @@ -560,6 +560,25 @@ class Listener(generic.View): neutronclient(request).delete_listener(listener_id) +@urls.register +class Pools(generic.View): + """API for load balancer pools. + + """ + url_regex = r'lbaas/pools/$' + + @rest_utils.ajax() + def post(self, request): + """Create a new pool. + + Creates a new pool as well as other optional resources such as + members and health monitor. + """ + kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id'), + 'listener_id': request.DATA.get('parentResourceId')} + return create_pool(request, **kwargs) + + @urls.register class Pool(generic.View): """API for retrieving a single pool. 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 21d0d2fa..5860b7ad 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 @@ -48,6 +48,7 @@ deleteListener: deleteListener, getPool: getPool, deletePool: deletePool, + createPool: createPool, getMembers: getMembers, getMember: getMember, getHealthMonitor: getHealthMonitor @@ -249,6 +250,21 @@ }); } + /** + * @name horizon.app.core.openstack-service-api.lbaasv2.createPool + * @description + * Create a new pool + * @param {object} spec + * Specifies the data used to create the new pool. + */ + + function createPool(spec) { + return apiService.post('/api/lbaas/pools/', spec) + .error(function () { + toastService.add('error', gettext('Unable to create pool.')); + }); + } + /** * @name horizon.app.core.openstack-service-api.lbaasv2.deletePool * @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 c620bb96..4c2bb19d 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 @@ -163,6 +163,14 @@ path: '/api/lbaas/listeners/1234', error: 'Unable to delete listener.', testInput: [ '1234' ] + }, + { + func: 'createPool', + method: 'post', + path: '/api/lbaas/pools/', + error: 'Unable to create pool.', + data: { name: 'pool-1' }, + testInput: [ { name: 'pool-1' } ] } ]; diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.js index bb6cc282..83d7a392 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.js @@ -28,7 +28,8 @@ 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', - 'horizon.dashboard.project.lbaasv2.listeners.actions.delete' + 'horizon.dashboard.project.lbaasv2.listeners.actions.delete', + 'horizon.dashboard.project.lbaasv2.pools.actions.create' ]; /** @@ -45,11 +46,13 @@ * @param gettext The horizon gettext function for translation. * @param loadBalancersService The LBaaS v2 load balancers service. * @param deleteService The LBaaS v2 listeners delete service. + * @param createPoolService The LBaaS v2 pools create service. * @returns Listeners row actions service object. */ function tableRowActions( - $q, $route, workflowModal, policy, gettext, loadBalancersService, deleteService + $q, $route, workflowModal, policy, gettext, loadBalancersService, deleteService, + createPoolService ) { var loadbalancerId, loadBalancerIsActionable, handler; @@ -82,6 +85,11 @@ template: { text: gettext('Edit') } + },{ + service: createPoolService.init(loadbalancerId, loadBalancerIsActionable).create, + template: { + text: gettext('Create Pool') + } },{ service: deleteService.init(loadbalancerId, loadBalancerIsActionable, handler), template: { diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.spec.js index 4c7f40a8..f25d025e 100644 --- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.spec.js +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/listeners/actions/row-actions.service.spec.js @@ -82,9 +82,10 @@ })); it('should define correct table row actions', function() { - expect(actions.length).toBe(2); + expect(actions.length).toBe(3); expect(actions[0].template.text).toBe('Edit'); - expect(actions[1].template.text).toBe('Delete Listener'); + expect(actions[1].template.text).toBe('Create Pool'); + expect(actions[2].template.text).toBe('Delete Listener'); }); it('should allow editing a listener of an ACTIVE load balancer', function() { diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js new file mode 100644 index 00000000..25115f13 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js @@ -0,0 +1,89 @@ +/* + * 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.pools') + .factory('horizon.dashboard.project.lbaasv2.pools.actions.create', createService); + + createService.$inject = [ + '$q', + '$location', + 'horizon.dashboard.project.lbaasv2.workflow.modal', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.framework.util.q.extensions', + 'horizon.framework.util.i18n.gettext' + ]; + + /** + * @ngDoc factory + * @name horizon.dashboard.project.lbaasv2.listeners.actions.createService + * @description + * Provides the service for creating a pool resource. + * @param $q The angular service for promises. + * @param $location The angular $location service. + * @param workflowModal The LBaaS workflow modal service. + * @param policy The horizon policy service. + * @param qExtensions Horizon extensions to the $q service. + * @param gettext The horizon gettext function for translation. + * @returns The load balancers pool create service. + */ + + function createService( + $q, $location, workflowModal, policy, qExtensions, gettext + ) { + var loadbalancerId, listenerId, statePromise; + + var create = workflowModal.init({ + controller: 'CreatePoolWizardController', + message: gettext('A new pool is being created.'), + handle: onCreate, + allowed: allowed + }); + + var service = { + init: init, + create: create + }; + + return service; + + ////////////// + + function init(_loadbalancerId_, _statePromise_) { + loadbalancerId = _loadbalancerId_; + statePromise = _statePromise_; + return service; + } + + function allowed(item) { + listenerId = item.id; + return $q.all([ + statePromise, + qExtensions.booleanAsPromise(!item.default_pool_id), + policy.ifAllowed({ rules: [['neutron', 'create_pool']] }) + ]); + } + + function onCreate(response) { + var poolId = response.data.id; + $location.path('project/ngloadbalancersv2/' + loadbalancerId + '/listeners/' + + listenerId + '/pools/' + poolId); + } + + } +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js new file mode 100644 index 00000000..f31db715 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js @@ -0,0 +1,111 @@ +/* + * 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 Create Pool Action Service', function() { + var scope, $q, $location, policy, init, createPoolService, defer; + + function allowed(item) { + spyOn(policy, 'ifAllowed').and.returnValue(true); + var promise = createPoolService.create.allowed(item); + var allowed; + promise.then(function() { + allowed = true; + }, function() { + allowed = false; + }); + scope.$apply(); + expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'create_pool']]}); + 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) { + var response = { + data: { + id: '9012' + } + }; + var modal = { + open: function() { + return { + result: { + then: function(func) { + func(response); + } + } + }; + } + }; + $provide.value('$modal', modal); + })); + + beforeEach(inject(function ($injector) { + scope = $injector.get('$rootScope').$new(); + $q = $injector.get('$q'); + policy = $injector.get('horizon.app.core.openstack-service-api.policy'); + $location = $injector.get('$location'); + createPoolService = $injector.get( + 'horizon.dashboard.project.lbaasv2.pools.actions.create'); + init = createPoolService.init; + defer = $q.defer(); + })); + + it('should define the correct service properties', function() { + expect(createPoolService.init).toBeDefined(); + expect(createPoolService.create).toBeDefined(); + }); + + it('should have the "allowed" and "perform" functions', function() { + expect(createPoolService.create.allowed).toBeDefined(); + expect(createPoolService.create.perform).toBeDefined(); + }); + + it('should allow creating a pool under an ACTIVE load balancer', function() { + defer.resolve(); + init('active', defer.promise); + expect(allowed({default_pool_id: ''})).toBe(true); + }); + + it('should not allow creating a pool under an NON-ACTIVE load balancer', function() { + defer.reject(); + init('non-active', defer.promise); + expect(allowed({default_pool_id: ''})).toBe(false); + }); + + it('should not allow creating a pool if a listener pool already exists', function() { + defer.resolve(); + init('active', defer.promise); + expect(allowed({default_pool_id: '1234'})).toBe(false); + }); + + it('should redirect after create', function() { + defer.resolve(); + spyOn($location, 'path').and.callThrough(); + init('1234', defer.promise).create.allowed({id: '5678'}); + createPoolService.create.perform(); + expect($location.path).toHaveBeenCalledWith( + 'project/ngloadbalancersv2/1234/listeners/5678/pools/9012'); + }); + + }); +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js new file mode 100644 index 00000000..e1cccda0 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js @@ -0,0 +1,44 @@ +/* + * 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.pools') + .controller('CreatePoolWizardController', CreatePoolWizardController); + + CreatePoolWizardController.$inject = [ + '$scope', + '$routeParams', + 'horizon.dashboard.project.lbaasv2.workflow.model', + 'horizon.dashboard.project.lbaasv2.workflow.workflow', + 'horizon.framework.util.i18n.gettext' + ]; + + function CreatePoolWizardController($scope, $routeParams, model, workflowService, gettext) { + var loadbalancerId = $routeParams.loadbalancerId; + var scope = $scope; + scope.model = model; + scope.submit = scope.model.submit; + scope.workflow = workflowService( + gettext('Create Pool'), + 'fa fa-cloud-download', + ['pool', 'members', 'monitor'] + ); + scope.model.initialize('pool', false, loadbalancerId, scope.launchContext.id); + } + +})(); diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.spec.js new file mode 100644 index 00000000..88c89358 --- /dev/null +++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/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 Create Pool Wizard Controller', function() { + var ctrl; + var model = { + submit: function() { + return 'created'; + }, + initialize: angular.noop + }; + var workflow = function() { + return 'foo'; + }; + var scope = { + launchContext: {id: '1234'} + }; + + 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('CreatePoolWizardController', { $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('created'); + }); + }); + +})(); 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 fc33ea37..29eb2e66 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 @@ -117,7 +117,7 @@ * @param id ID of the resource being edited. */ - function initialize(resource, id, loadBalancerId) { + function initialize(resource, id, loadBalancerId, parentResourceId) { var promise; model.certificatesError = false; @@ -133,6 +133,7 @@ model.spec = { loadbalancer_id: loadBalancerId, + parentResourceId: parentResourceId, loadbalancer: { name: null, description: null, @@ -206,6 +207,17 @@ ]).then(initMemberAddresses); model.context.submit = createListener; break; + case 'createpool': + // We get the listener details here because we need to know the listener protocol + // in order to default the new pool's protocol to match. + promise = $q.all([ + lbaasv2API.getListener(model.spec.parentResourceId).then(onGetListener), + neutronAPI.getSubnets().then(onGetSubnets), + neutronAPI.getPorts().then(onGetPorts), + novaAPI.getServers().then(onGetServers) + ]).then(initMemberAddresses); + model.context.submit = createPool; + break; case 'editloadbalancer': promise = $q.all([ lbaasv2API.getLoadBalancer(model.context.id).then(onGetLoadBalancer), @@ -268,6 +280,10 @@ return lbaasv2API.createListener(spec); } + function createPool(spec) { + return lbaasv2API.createPool(spec); + } + function editLoadBalancer(spec) { return lbaasv2API.editLoadBalancer(model.context.id, spec); } @@ -469,36 +485,39 @@ } function onGetListener(response) { - var resources = response.data; + var result = response.data; - setListenerSpec(resources.listener); - model.visibleResources.push('listener'); - model.spec.loadbalancer_id = resources.listener.loadbalancers[0].id; + setListenerSpec(result.listener || result); - if (resources.listener.protocol === 'TERMINATED_HTTPS') { - keymanagerPromise.then(prepareCertificates).then(function addAvailableCertificates() { - resources.listener.sni_container_refs.forEach(function addAvailableCertificate(ref) { - model.certificates.filter(function matchCertificate(cert) { - return cert.id === ref; - }).forEach(function addCertificate(cert) { - model.spec.certificates.push(cert); + if (result.listener) { + model.visibleResources.push('listener'); + model.spec.loadbalancer_id = result.listener.loadbalancers[0].id; + + if (result.listener.protocol === 'TERMINATED_HTTPS') { + keymanagerPromise.then(prepareCertificates).then(function addAvailableCertificates() { + result.listener.sni_container_refs.forEach(function addAvailableCertificate(ref) { + model.certificates.filter(function matchCertificate(cert) { + return cert.id === ref; + }).forEach(function addCertificate(cert) { + model.spec.certificates.push(cert); + }); }); }); - }); - model.visibleResources.push('certificates'); + model.visibleResources.push('certificates'); + } } - if (resources.pool) { - setPoolSpec(resources.pool); + if (result.pool) { + setPoolSpec(result.pool); model.visibleResources.push('pool'); model.visibleResources.push('members'); - if (resources.members) { - setMembersSpec(resources.members); + if (result.members) { + setMembersSpec(result.members); } - if (resources.monitor) { - setMonitorSpec(resources.monitor); + if (result.monitor) { + setMonitorSpec(result.monitor); model.visibleResources.push('monitor'); } } 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 9dcec7b7..95444348 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 @@ -18,6 +18,7 @@ describe('LBaaS v2 Workflow Model Service', function() { var model, $q, scope, listenerResources, barbicanEnabled, certificatesError; + var includeChildResources = true; beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); @@ -111,7 +112,9 @@ }, getListener: function() { var deferred = $q.defer(); - deferred.resolve({ data: listenerResources }); + var listenerData; + listenerData = includeChildResources ? listenerResources : listenerResources.listener; + deferred.resolve({ data: listenerData }); return deferred.promise; }, getPool: function() { @@ -178,6 +181,9 @@ }, editListener: function(id, spec) { return spec; + }, + createPool: function(spec) { + return spec; } }); @@ -421,6 +427,44 @@ }); }); + describe('Post initialize model (create pool)', function() { + + beforeEach(function() { + includeChildResources = false; + model.initialize('pool', false, '1234', '5678'); + scope.$apply(); + }); + + it('should initialize model properties', function() { + expect(model.initializing).toBe(false); + expect(model.initialized).toBe(true); + expect(model.subnets.length).toBe(2); + expect(model.members.length).toBe(2); + expect(model.certificates.length).toBe(0); + expect(model.listenerPorts.length).toBe(0); + expect(model.spec).toBeDefined(); + expect(model.spec.loadbalancer_id).toBe('1234'); + expect(model.spec.parentResourceId).toBe('5678'); + expect(model.spec.loadbalancer).toBeDefined(); + expect(model.spec.listener).toBeDefined(); + expect(model.spec.pool).toBeDefined(); + expect(model.spec.members.length).toBe(0); + expect(model.spec.certificates).toEqual([]); + expect(model.spec.monitor).toBeDefined(); + expect(model.certificatesError).toBe(false); + }); + + it('should initialize names', function() { + expect(model.spec.pool.name).toBe('Pool 1'); + }); + + it('should initialize context properties', function() { + expect(model.context.resource).toBe('pool'); + expect(model.context.id).toBeFalsy(); + expect(model.context.submit).toBeDefined(); + }); + }); + describe('Post initialize model (edit loadbalancer)', function() { beforeEach(function() { @@ -526,6 +570,7 @@ describe('Post initialize model (edit listener)', function() { beforeEach(function() { + includeChildResources = true; model.initialize('listener', '1234'); scope.$apply(); }); @@ -644,7 +689,7 @@ // This is here to ensure that as people add/change spec properties, they don't forget // to implement tests for them. it('has the right number of properties', function() { - expect(Object.keys(model.spec).length).toBe(7); + expect(Object.keys(model.spec).length).toBe(8); expect(Object.keys(model.spec.loadbalancer).length).toBe(4); expect(Object.keys(model.spec.listener).length).toBe(5); expect(Object.keys(model.spec.pool).length).toBe(5); @@ -652,10 +697,14 @@ expect(model.spec.members).toEqual([]); }); - it('sets load balancer ID to null', function() { + it('sets load balancer ID to undefined', function() { expect(model.spec.loadbalancer_id).toBeUndefined(); }); + it('sets parent resource ID to undefined', function() { + expect(model.spec.parentResourceId).toBeUndefined(); + }); + it('sets load balancer name to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); }); @@ -832,6 +881,7 @@ describe('context (edit listener)', function() { beforeEach(function() { + includeChildResources = true; model.initialize('listener', '1'); scope.$apply(); }); @@ -843,6 +893,20 @@ }); }); + describe('context (create pool)', function() { + + beforeEach(function() { + model.initialize('pool', false, '1234', '5678'); + scope.$apply(); + }); + + it('should initialize context', function() { + expect(model.context.resource).toBe('pool'); + expect(model.context.id).toBeFalsy(); + expect(model.context.submit.name).toBe('createPool'); + }); + }); + describe('Model submit function (create loadbalancer)', function() { beforeEach(function() { @@ -1297,9 +1361,192 @@ }); }); + describe('Model submit function (create pool)', function() { + + beforeEach(function() { + includeChildResources = false; + model.initialize('pool', false, '1234', '5678'); + scope.$apply(); + }); + + it('should set final spec properties', function() { + model.spec.listener.protocol = 'TCP'; + model.spec.pool.name = 'pool name'; + model.spec.pool.description = 'pool description'; + model.spec.pool.method = 'LEAST_CONNECTIONS'; + model.spec.members = [{ + address: { ip: '1.2.3.4', subnet: '1' }, + addresses: [{ ip: '1.2.3.4', subnet: '1' }, + { ip: '2.3.4.5', subnet: '2' }], + id: '1', + name: 'foo', + port: 80, + weight: 1 + }, { + id: 'external-member-0', + address: '2.3.4.5', + subnet: null, + port: 80, + weight: 1 + }, { + id: 'external-member-1', + address: null, + subnet: null, + port: 80, + weight: 1 + }, { + id: 'external-member-2', + address: '3.4.5.6', + subnet: { id: '1' }, + port: 80, + weight: 1 + }]; + model.spec.monitor.type = 'PING'; + model.spec.monitor.interval = 1; + model.spec.monitor.retry = 1; + model.spec.monitor.timeout = 1; + model.spec.certificates = [{ + id: 'container1', + name: 'foo', + expiration: '2015-03-26T21:10:45.417835' + }]; + + var finalSpec = model.submit(); + + expect(finalSpec.pool.name).toBe('pool name'); + expect(finalSpec.pool.description).toBe('pool description'); + expect(finalSpec.pool.protocol).toBe('TCP'); + expect(finalSpec.pool.method).toBe('LEAST_CONNECTIONS'); + + expect(finalSpec.members.length).toBe(3); + expect(finalSpec.members[0].address).toBe('1.2.3.4'); + expect(finalSpec.members[0].subnet).toBe('1'); + expect(finalSpec.members[0].port).toBe(80); + expect(finalSpec.members[0].weight).toBe(1); + expect(finalSpec.members[0].id).toBe('1'); + expect(finalSpec.members[0].addresses).toBeUndefined(); + expect(finalSpec.members[0].name).toBeUndefined(); + expect(finalSpec.members[0].allocatedMember).toBeUndefined(); + expect(finalSpec.members[1].id).toBe('external-member-0'); + expect(finalSpec.members[1].address).toBe('2.3.4.5'); + expect(finalSpec.members[1].subnet).toBeUndefined(); + expect(finalSpec.members[1].port).toBe(80); + expect(finalSpec.members[1].weight).toBe(1); + expect(finalSpec.members[1].allocatedMember).toBeUndefined(); + expect(finalSpec.members[2].id).toBe('external-member-2'); + expect(finalSpec.members[2].address).toBe('3.4.5.6'); + expect(finalSpec.members[2].subnet).toBe('1'); + expect(finalSpec.members[2].port).toBe(80); + expect(finalSpec.members[2].weight).toBe(1); + expect(finalSpec.members[2].allocatedMember).toBeUndefined(); + + expect(finalSpec.monitor.type).toBe('PING'); + expect(finalSpec.monitor.interval).toBe(1); + expect(finalSpec.monitor.retry).toBe(1); + expect(finalSpec.monitor.timeout).toBe(1); + expect(finalSpec.certificates).toBeUndefined(); + }); + + it('should delete listener if any required property is not set', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = ''; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeUndefined(); + expect(finalSpec.pool).toBeUndefined(); + }); + + it('should delete certificates if not using TERMINATED_HTTPS', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = 80; + model.spec.certificates = [{id: '1'}]; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeDefined(); + expect(finalSpec.certificates).toBeUndefined(); + }); + + it('should delete pool if any required property is not set', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = 80; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeDefined(); + expect(finalSpec.pool).toBeUndefined(); + }); + + it('should delete members if none selected', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = 80; + model.spec.pool.method = 'LEAST_CONNECTIONS'; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeDefined(); + expect(finalSpec.pool).toBeDefined(); + expect(finalSpec.members).toBeUndefined(); + }); + + it('should delete members if no members are valid', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = 80; + model.spec.pool.method = 'LEAST_CONNECTIONS'; + model.spec.members = [{ + id: 'foo', + address: '2.3.4.5', + weight: 1 + }]; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeDefined(); + expect(finalSpec.pool).toBeDefined(); + expect(finalSpec.members).toBeUndefined(); + }); + + it('should delete monitor if any required property not set', function() { + model.spec.loadbalancer.ip = '1.2.3.4'; + model.spec.loadbalancer.subnet = model.subnets[0]; + model.spec.listener.protocol = 'HTTP'; + model.spec.listener.port = 80; + model.spec.pool.method = 'LEAST_CONNECTIONS'; + model.spec.monitor.type = 'PING'; + model.spec.monitor.interval = 1; + model.spec.monitor.retry = 1; + model.spec.monitor.timeout = null; + + var finalSpec = model.submit(); + + expect(finalSpec.loadbalancer).toBeDefined(); + expect(finalSpec.listener).toBeDefined(); + expect(finalSpec.pool).toBeDefined(); + expect(finalSpec.members).toBeUndefined(); + expect(finalSpec.monitor).toBeUndefined(); + }); + }); + describe('Model submit function (edit listener)', function() { beforeEach(function() { + includeChildResources = true; model.initialize('listener', '1234'); scope.$apply(); });