Add the Angular LBaaS V2 'Create Pool' workflow

This change adds the Create Pool workflow action to the
listeners table and the listeners detail page.  This wizard
allows you to create a new pool, as well as any of the pool's
child resources, including members and a health monitor.

Partially-Implements: blueprint horizon-lbaas-v2-ui
Change-Id: I934921f207373311b8b65f2ba34546238e961ac9
This commit is contained in:
Lucas Palm 2016-03-03 14:03:01 -06:00 committed by Justin Pomeroy
parent a7f1b762ed
commit d43b71b443
11 changed files with 652 additions and 27 deletions

View File

@ -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.

View File

@ -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

View File

@ -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' } ]
}
];

View File

@ -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: {

View File

@ -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() {

View File

@ -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);
}
}
})();

View File

@ -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');
});
});
})();

View File

@ -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);
}
})();

View File

@ -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');
});
});
})();

View File

@ -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');
}
}

View File

@ -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();
});