Add the angular LBaaS V2 Edit Action for Listeners
This change implements the edit row action service for the listeners table. The edit action of a listener includes the ability to not only edit the listener itself, but all resources underneath it in the load balancer hierarchy. Partially-Implements: blueprint horizon-lbaas-v2-ui Change-Id: I5fcb20eecbee580f9db5c71da5a2ec84a6f359f9
This commit is contained in:
parent
d424350bfa
commit
9a88246fe6
|
@ -118,8 +118,19 @@ def add_member(request, **kwargs):
|
|||
|
||||
"""
|
||||
data = request.DATA
|
||||
members = data['members']
|
||||
index = kwargs['index']
|
||||
members = data.get('members')
|
||||
|
||||
if kwargs.get('members_to_add'):
|
||||
members_to_add = kwargs['members_to_add']
|
||||
index = [members.index(member) for member in members
|
||||
if member['id'] == members_to_add[0]][0]
|
||||
pool_id = data['pool'].get('id')
|
||||
loadbalancer_id = data.get('loadbalancer_id')
|
||||
else:
|
||||
index = kwargs.get('index')
|
||||
pool_id = kwargs.get('pool_id')
|
||||
loadbalancer_id = kwargs.get('loadbalancer_id')
|
||||
|
||||
member = members[index]
|
||||
memberSpec = {
|
||||
'address': member['address'],
|
||||
|
@ -128,23 +139,55 @@ def add_member(request, **kwargs):
|
|||
}
|
||||
if member.get('weight'):
|
||||
memberSpec['weight'] = member['weight']
|
||||
|
||||
member = neutronclient(request).create_lbaas_member(
|
||||
kwargs['pool_id'], {'member': memberSpec}).get('member')
|
||||
pool_id, {'member': memberSpec}).get('member')
|
||||
|
||||
index += 1
|
||||
if len(members) > index:
|
||||
args = (request, kwargs['loadbalancer_id'], add_member)
|
||||
kwargs = {'callback_kwargs': {'pool_id': kwargs['pool_id'],
|
||||
if kwargs.get('members_to_add'):
|
||||
args = (request, loadbalancer_id, update_member_list)
|
||||
members_to_add = kwargs['members_to_add']
|
||||
members_to_add.pop(0)
|
||||
kwargs = {'callback_kwargs': {
|
||||
'existing_members': kwargs.get('existing_members'),
|
||||
'members_to_add': members_to_add,
|
||||
'members_to_delete': kwargs.get('members_to_delete')}}
|
||||
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
|
||||
elif len(members) > index:
|
||||
args = (request, loadbalancer_id, add_member)
|
||||
kwargs = {'callback_kwargs': {'pool_id': pool_id,
|
||||
'index': index}}
|
||||
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
|
||||
elif data.get('monitor'):
|
||||
args = (request, kwargs['loadbalancer_id'], add_monitor)
|
||||
kwargs = {'callback_kwargs': {'pool_id': kwargs['pool_id']}}
|
||||
args = (request, loadbalancer_id, add_monitor)
|
||||
kwargs = {'callback_kwargs': {'pool_id': pool_id}}
|
||||
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
|
||||
|
||||
return member
|
||||
|
||||
|
||||
def remove_member(request, **kwargs):
|
||||
"""Remove a member from the pool.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
loadbalancer_id = data.get('loadbalancer_id')
|
||||
pool_id = data['pool']['id']
|
||||
|
||||
if kwargs.get('members_to_delete'):
|
||||
members_to_delete = kwargs['members_to_delete']
|
||||
member_id = members_to_delete.pop(0)
|
||||
|
||||
neutronclient(request).delete_lbaas_member(member_id, pool_id)
|
||||
|
||||
args = (request, loadbalancer_id, update_member_list)
|
||||
kwargs = {'callback_kwargs': {
|
||||
'existing_members': kwargs.get('existing_members'),
|
||||
'members_to_add': kwargs.get('members_to_add'),
|
||||
'members_to_delete': members_to_delete}}
|
||||
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
|
||||
|
||||
|
||||
def add_monitor(request, **kwargs):
|
||||
"""Create a new health monitor for a pool.
|
||||
|
||||
|
@ -167,6 +210,140 @@ def add_monitor(request, **kwargs):
|
|||
{'healthmonitor': monitorSpec}).get('healthmonitor')
|
||||
|
||||
|
||||
def update_loadbalancer(request, **kwargs):
|
||||
"""Update a load balancer.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
spec = {}
|
||||
loadbalancer_id = kwargs.get('loadbalancer_id')
|
||||
|
||||
if data['loadbalancer'].get('name'):
|
||||
spec['name'] = data['loadbalancer']['name']
|
||||
if data['loadbalancer'].get('description'):
|
||||
spec['description'] = data['loadbalancer']['description']
|
||||
return neutronclient(request).update_loadbalancer(
|
||||
loadbalancer_id, {'loadbalancer': spec}).get('loadbalancer')
|
||||
|
||||
|
||||
def update_listener(request, **kwargs):
|
||||
"""Update a listener.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
listener_spec = {}
|
||||
listener_id = data['listener'].get('id')
|
||||
loadbalancer_id = data.get('loadbalancer_id')
|
||||
|
||||
if data['listener'].get('name'):
|
||||
listener_spec['name'] = data['listener']['name']
|
||||
if data['listener'].get('description'):
|
||||
listener_spec['description'] = data['listener']['description']
|
||||
|
||||
listener = neutronclient(request).update_listener(
|
||||
listener_id, {'listener': listener_spec}).get('listener')
|
||||
|
||||
if data.get('pool'):
|
||||
args = (request, loadbalancer_id, update_pool)
|
||||
thread.start_new_thread(poll_loadbalancer_status, args)
|
||||
|
||||
return listener
|
||||
|
||||
|
||||
def update_pool(request, **kwargs):
|
||||
"""Update a pool.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
pool_spec = {}
|
||||
pool_id = data['pool'].get('id')
|
||||
loadbalancer_id = data.get('loadbalancer_id')
|
||||
|
||||
if data['pool'].get('name'):
|
||||
pool_spec['name'] = data['pool']['name']
|
||||
if data['pool'].get('description'):
|
||||
pool_spec['description'] = data['pool']['description']
|
||||
|
||||
pools = neutronclient(request).update_lbaas_pool(
|
||||
pool_id, {'pool': pool_spec}).get('pools')
|
||||
|
||||
# Assemble the lists of member id's to add and remove, if any exist
|
||||
tenant_id = request.user.project_id
|
||||
new_members = data.get('members', [])
|
||||
existing_members = neutronclient(request).list_lbaas_members(
|
||||
pool_id, tenant_id=tenant_id).get('members')
|
||||
new_member_ids = [member['id'] for member in new_members]
|
||||
existing_member_ids = [member['id'] for member in existing_members]
|
||||
members_to_add = [member_id for member_id in new_member_ids
|
||||
if member_id not in existing_member_ids]
|
||||
members_to_delete = [member_id for member_id in existing_member_ids
|
||||
if member_id not in new_member_ids]
|
||||
|
||||
if members_to_add or members_to_delete:
|
||||
args = (request, loadbalancer_id, update_member_list)
|
||||
kwargs = {'callback_kwargs': {'existing_members': existing_members,
|
||||
'members_to_add': members_to_add,
|
||||
'members_to_delete': members_to_delete}}
|
||||
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
|
||||
elif data.get('monitor'):
|
||||
args = (request, loadbalancer_id, update_monitor)
|
||||
thread.start_new_thread(poll_loadbalancer_status, args)
|
||||
|
||||
return pools
|
||||
|
||||
|
||||
def update_monitor(request, **kwargs):
|
||||
"""Update a health monitor.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
monitor_spec = {}
|
||||
monitor_id = data['monitor']['id']
|
||||
|
||||
if data['monitor'].get('interval'):
|
||||
monitor_spec['delay'] = data['monitor']['interval']
|
||||
if data['monitor'].get('timeout'):
|
||||
monitor_spec['timeout'] = data['monitor']['timeout']
|
||||
if data['monitor'].get('retry'):
|
||||
monitor_spec['max_retries'] = data['monitor']['retry']
|
||||
if data['monitor'].get('method'):
|
||||
monitor_spec['http_method'] = data['monitor']['method']
|
||||
if data['monitor'].get('path'):
|
||||
monitor_spec['url_path'] = data['monitor']['path']
|
||||
if data['monitor'].get('status'):
|
||||
monitor_spec['expected_codes'] = data['monitor']['status']
|
||||
|
||||
healthmonitor = neutronclient(request).update_lbaas_healthmonitor(
|
||||
monitor_id, {'healthmonitor': monitor_spec}).get('healthmonitor')
|
||||
|
||||
return healthmonitor
|
||||
|
||||
|
||||
def update_member_list(request, **kwargs):
|
||||
"""Update the list of members by adding or removing the necessary members.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
loadbalancer_id = data.get('loadbalancer_id')
|
||||
existing_members = kwargs.get('existing_members')
|
||||
members_to_add = kwargs.get('members_to_add')
|
||||
members_to_delete = kwargs.get('members_to_delete')
|
||||
|
||||
if members_to_add:
|
||||
kwargs = {'existing_members': existing_members,
|
||||
'members_to_add': members_to_add,
|
||||
'members_to_delete': members_to_delete}
|
||||
add_member(request, **kwargs)
|
||||
elif members_to_delete:
|
||||
kwargs = {'existing_members': existing_members,
|
||||
'members_to_add': members_to_add,
|
||||
'members_to_delete': members_to_delete}
|
||||
remove_member(request, **kwargs)
|
||||
elif data.get('monitor'):
|
||||
args = (request, loadbalancer_id, update_monitor)
|
||||
thread.start_new_thread(poll_loadbalancer_status, args)
|
||||
|
||||
|
||||
@urls.register
|
||||
class LoadBalancers(generic.View):
|
||||
"""API for load balancers.
|
||||
|
@ -217,7 +394,7 @@ class LoadBalancers(generic.View):
|
|||
|
||||
@urls.register
|
||||
class LoadBalancer(generic.View):
|
||||
"""API for retrieving a single load balancer.
|
||||
"""API for retrieving, updating, and deleting a single load balancer.
|
||||
|
||||
"""
|
||||
url_regex = r'lbaas/loadbalancers/(?P<loadbalancer_id>[^/]+)/$'
|
||||
|
@ -236,14 +413,8 @@ class LoadBalancer(generic.View):
|
|||
"""Edit a load balancer.
|
||||
|
||||
"""
|
||||
data = request.DATA
|
||||
spec = {}
|
||||
if data['loadbalancer'].get('name'):
|
||||
spec['name'] = data['loadbalancer']['name']
|
||||
if data['loadbalancer'].get('description'):
|
||||
spec['description'] = data['loadbalancer']['description']
|
||||
return neutronclient(request).update_loadbalancer(
|
||||
loadbalancer_id, {'loadbalancer': spec}).get('loadbalancer')
|
||||
kwargs = {'loadbalancer_id': loadbalancer_id}
|
||||
update_loadbalancer(request, **kwargs)
|
||||
|
||||
|
||||
@urls.register
|
||||
|
@ -280,7 +451,7 @@ class Listeners(generic.View):
|
|||
|
||||
@urls.register
|
||||
class Listener(generic.View):
|
||||
"""API for retrieving a single listener.
|
||||
"""API for retrieving, updating, and deleting a single listener.
|
||||
|
||||
"""
|
||||
url_regex = r'lbaas/listeners/(?P<listener_id>[^/]+)/$'
|
||||
|
@ -289,10 +460,48 @@ class Listener(generic.View):
|
|||
def get(self, request, listener_id):
|
||||
"""Get a specific listener.
|
||||
|
||||
If the param 'includeChildResources' is passed in as true, the details
|
||||
of all resources that exist under the listener will be returned along
|
||||
with the listener details.
|
||||
|
||||
http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915
|
||||
"""
|
||||
lb = neutronclient(request).show_listener(listener_id)
|
||||
return lb.get('listener')
|
||||
listener = neutronclient(request).show_listener(
|
||||
listener_id).get('listener')
|
||||
|
||||
if request.GET.get('includeChildResources'):
|
||||
resources = {}
|
||||
resources['listener'] = listener
|
||||
|
||||
if listener.get('default_pool_id'):
|
||||
pool_id = listener['default_pool_id']
|
||||
pool = neutronclient(request).show_lbaas_pool(
|
||||
pool_id).get('pool')
|
||||
resources['pool'] = pool
|
||||
|
||||
if pool.get('members'):
|
||||
tenant_id = request.user.project_id
|
||||
members = neutronclient(request).list_lbaas_members(
|
||||
pool_id, tenant_id=tenant_id).get('members')
|
||||
resources['members'] = members
|
||||
|
||||
if pool.get('healthmonitor_id'):
|
||||
monitor_id = pool['healthmonitor_id']
|
||||
monitor = neutronclient(request).show_lbaas_healthmonitor(
|
||||
monitor_id).get('healthmonitor')
|
||||
resources['monitor'] = monitor
|
||||
|
||||
return resources
|
||||
else:
|
||||
return listener
|
||||
|
||||
@rest_utils.ajax()
|
||||
def put(self, request, listener_id):
|
||||
"""Edit a listener as well as any resources below it.
|
||||
|
||||
"""
|
||||
kwargs = {'listener_id': listener_id}
|
||||
update_listener(request, **kwargs)
|
||||
|
||||
|
||||
@urls.register
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
editLoadBalancer: editLoadBalancer,
|
||||
getListeners: getListeners,
|
||||
getListener: getListener,
|
||||
editListener: editListener,
|
||||
getPool: getPool,
|
||||
getMembers: getMembers,
|
||||
getMember: getMember,
|
||||
|
@ -110,7 +111,7 @@
|
|||
*/
|
||||
|
||||
function editLoadBalancer(id, spec) {
|
||||
return apiService.put('/api/lbaas/loadbalancers/' + id + '/', spec)
|
||||
return apiService.put('/api/lbaas/loadbalancers/' + id, spec)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to update load balancer.'));
|
||||
});
|
||||
|
@ -146,15 +147,37 @@
|
|||
* Get a single listener by ID.
|
||||
* @param {string} id
|
||||
* Specifies the id of the listener to request.
|
||||
* @param {boolean} includeChildResources
|
||||
* If true, all child resources below the listener will be included in the response.
|
||||
*/
|
||||
|
||||
function getListener(id) {
|
||||
return apiService.get('/api/lbaas/listeners/' + id)
|
||||
function getListener(id, includeChildResources) {
|
||||
var params = includeChildResources
|
||||
? {'params': {'includeChildResources': includeChildResources}}
|
||||
: {};
|
||||
return apiService.get('/api/lbaas/listeners/' + id, params)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to retrieve listener.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.app.core.openstack-service-api.lbaasv2.editListener
|
||||
* @description
|
||||
* Edit a listener
|
||||
* @param {string} id
|
||||
* Specifies the id of the listener to update.
|
||||
* @param {object} spec
|
||||
* Specifies the data used to update the listener.
|
||||
*/
|
||||
|
||||
function editListener(id, spec) {
|
||||
return apiService.put('/api/lbaas/listeners/' + id, spec)
|
||||
.error(function () {
|
||||
toastService.add('error', gettext('Unable to update listener.'));
|
||||
});
|
||||
}
|
||||
|
||||
// Pools
|
||||
|
||||
/**
|
||||
|
|
|
@ -76,9 +76,26 @@
|
|||
"func": "getListener",
|
||||
"method": "get",
|
||||
"path": "/api/lbaas/listeners/1234",
|
||||
"data": {
|
||||
"params": {
|
||||
"includeChildResources": true
|
||||
}
|
||||
},
|
||||
"error": "Unable to retrieve listener.",
|
||||
"testInput": [
|
||||
'1234'
|
||||
'1234',
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"func": "getListener",
|
||||
"method": "get",
|
||||
"path": "/api/lbaas/listeners/1234",
|
||||
"data": {},
|
||||
"error": "Unable to retrieve listener.",
|
||||
"testInput": [
|
||||
'1234',
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -131,13 +148,24 @@
|
|||
{
|
||||
"func": "editLoadBalancer",
|
||||
"method": "put",
|
||||
"path": "/api/lbaas/loadbalancers/1234/",
|
||||
"path": "/api/lbaas/loadbalancers/1234",
|
||||
"error": "Unable to update load balancer.",
|
||||
"data": { "name": "loadbalancer-1" },
|
||||
"testInput": [
|
||||
"1234",
|
||||
{ "name": "loadbalancer-1" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"func": "editListener",
|
||||
"method": "put",
|
||||
"path": "/api/lbaas/listeners/1234",
|
||||
"error": "Unable to update listener.",
|
||||
"data": { "name": "listener-1" },
|
||||
"testInput": [
|
||||
"1234",
|
||||
{ "name": "listener-1" }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
div.tab-pane > dl {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
actions + dl {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load Balancer Wizard */
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.loadbalancers')
|
||||
.controller('EditListenerWizardController', EditListenerWizardController);
|
||||
|
||||
EditListenerWizardController.$inject = [
|
||||
'$scope',
|
||||
'$q',
|
||||
'horizon.dashboard.project.lbaasv2.workflow.model',
|
||||
'horizon.dashboard.project.lbaasv2.workflow.workflow',
|
||||
'horizon.framework.util.i18n.gettext'
|
||||
];
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name EditListenerWizardController
|
||||
*
|
||||
* @description
|
||||
* Controller for the LBaaS v2 edit listener wizard.
|
||||
*
|
||||
* @param $scope The angular scope object.
|
||||
* @param $q The angular service for promises.
|
||||
* @param model The LBaaS V2 workflow model service.
|
||||
* @param workflowService The LBaaS V2 workflow service.
|
||||
* @param gettext The horizon gettext function for translation.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function EditListenerWizardController($scope, $q, model, workflowService, gettext) {
|
||||
var scope = $scope;
|
||||
var defer = $q.defer();
|
||||
scope.model = model;
|
||||
scope.submit = scope.model.submit;
|
||||
scope.workflow = workflowService(
|
||||
gettext('Update Listener'),
|
||||
'fa fa-pencil', ['listener'],
|
||||
defer.promise);
|
||||
scope.model.initialize('listener', scope.launchContext.id).then(addSteps).then(ready);
|
||||
|
||||
function addSteps() {
|
||||
var steps = scope.model.visibleResources;
|
||||
steps.map(getStep).forEach(function addStep(step) {
|
||||
if (!stepExists(step.id)) {
|
||||
scope.workflow.append(step);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getStep(id) {
|
||||
return scope.workflow.allSteps.filter(function findStep(step) {
|
||||
return step.id === id;
|
||||
})[0];
|
||||
}
|
||||
|
||||
function stepExists(id) {
|
||||
return scope.workflow.steps.some(function exists(step) {
|
||||
return step.id === id;
|
||||
});
|
||||
}
|
||||
|
||||
function ready() {
|
||||
defer.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 Listener Wizard Controller', function() {
|
||||
var ctrl, workflowSpy, $q, scope;
|
||||
var model = {
|
||||
submit: function() {
|
||||
return 'updated';
|
||||
},
|
||||
initialize: function() {
|
||||
var defer = $q.defer();
|
||||
defer.resolve();
|
||||
return defer.promise;
|
||||
}
|
||||
};
|
||||
var workflow = {
|
||||
steps: [{id: 'listener'}],
|
||||
allSteps: [{id: 'listener'}, {id: 'pool'}, {id: 'monitor'}],
|
||||
append: angular.noop
|
||||
};
|
||||
|
||||
beforeEach(module('horizon.framework.util'));
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
beforeEach(module(function ($provide) {
|
||||
workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow);
|
||||
$provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model);
|
||||
$provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy);
|
||||
}));
|
||||
beforeEach(inject(function ($controller, $injector) {
|
||||
$q = $injector.get('$q');
|
||||
scope = $injector.get('$rootScope').$new();
|
||||
scope.launchContext = { id: '1234' };
|
||||
spyOn(model, 'initialize').and.callThrough();
|
||||
ctrl = $controller('EditListenerWizardController', { $scope: scope });
|
||||
}));
|
||||
|
||||
it('defines the controller', function() {
|
||||
expect(ctrl).toBeDefined();
|
||||
});
|
||||
|
||||
it('calls initialize on the given model', function() {
|
||||
expect(model.initialize).toHaveBeenCalledWith('listener', '1234');
|
||||
});
|
||||
|
||||
it('sets scope.workflow to the given workflow', function() {
|
||||
expect(scope.workflow).toBe(workflow);
|
||||
});
|
||||
|
||||
it('initializes workflow with correct properties', function() {
|
||||
expect(workflowSpy).toHaveBeenCalledWith('Update Listener',
|
||||
'fa fa-pencil', ['listener'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('defines scope.submit', function() {
|
||||
expect(scope.submit).toBe(model.submit);
|
||||
expect(scope.submit()).toBe('updated');
|
||||
});
|
||||
|
||||
it('adds necessary steps after initializing', function() {
|
||||
model.visibleResources = ['listener', 'pool', 'monitor'];
|
||||
spyOn(workflow, 'append');
|
||||
scope.$apply();
|
||||
|
||||
expect(workflow.append).toHaveBeenCalledWith({id: 'pool'});
|
||||
expect(workflow.append).toHaveBeenCalledWith({id: 'monitor'});
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.listeners')
|
||||
.factory('horizon.dashboard.project.lbaasv2.listeners.actions.rowActions',
|
||||
tableRowActions);
|
||||
|
||||
tableRowActions.$inject = [
|
||||
'$q',
|
||||
'$route',
|
||||
'horizon.dashboard.project.lbaasv2.workflow.modal',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
|
||||
];
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @ngname horizon.dashboard.project.lbaasv2.listeners.actions.rowActions
|
||||
*
|
||||
* @description
|
||||
* Provides the service for the Listener table row actions.
|
||||
*
|
||||
* @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.
|
||||
* @param loadBalancersService The LBaaS v2 load balancers service.
|
||||
* @returns Listeners row actions service object.
|
||||
*/
|
||||
|
||||
function tableRowActions($q, $route, workflowModal, policy, gettext, loadBalancersService) {
|
||||
|
||||
var edit = workflowModal.init({
|
||||
controller: 'EditListenerWizardController',
|
||||
message: gettext('The listener has been updated.'),
|
||||
handle: onEdit,
|
||||
allowed: canEdit
|
||||
});
|
||||
|
||||
var service = {
|
||||
actions: actions,
|
||||
init: init
|
||||
};
|
||||
|
||||
var loadBalancerIsActive;
|
||||
|
||||
return service;
|
||||
|
||||
///////////////
|
||||
|
||||
function init(loadbalancerId) {
|
||||
loadBalancerIsActive = loadBalancersService.isActive(loadbalancerId);
|
||||
return service;
|
||||
}
|
||||
|
||||
function actions() {
|
||||
return [{
|
||||
service: edit,
|
||||
template: {
|
||||
text: gettext('Edit')
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
function canEdit(/*item*/) {
|
||||
return $q.all([
|
||||
loadBalancerIsActive,
|
||||
policy.ifAllowed({ rules: [['neutron', 'update_listener']] })
|
||||
]);
|
||||
}
|
||||
|
||||
function onEdit(/*response*/) {
|
||||
$route.reload();
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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 Listeners Table Row Actions Service', function() {
|
||||
var scope, $route, $q, actions, policy, init;
|
||||
|
||||
function canEdit(item) {
|
||||
spyOn(policy, 'ifAllowed').and.returnValue(true);
|
||||
var promise = actions[0].service.allowed(item);
|
||||
var allowed;
|
||||
promise.then(function() {
|
||||
allowed = true;
|
||||
}, function() {
|
||||
allowed = false;
|
||||
});
|
||||
scope.$apply();
|
||||
expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_listener']]});
|
||||
return allowed;
|
||||
}
|
||||
|
||||
function isActiveMock(id) {
|
||||
if (id === 'active') {
|
||||
return $q.when();
|
||||
} else {
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(module('horizon.framework.util'));
|
||||
beforeEach(module('horizon.framework.conf'));
|
||||
beforeEach(module('horizon.framework.widgets.toast'));
|
||||
beforeEach(module('horizon.app.core.openstack-service-api'));
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
var response = {
|
||||
data: {
|
||||
id: '1'
|
||||
}
|
||||
};
|
||||
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');
|
||||
$route = $injector.get('$route');
|
||||
policy = $injector.get('horizon.app.core.openstack-service-api.policy');
|
||||
var rowActionsService = $injector.get(
|
||||
'horizon.dashboard.project.lbaasv2.listeners.actions.rowActions');
|
||||
actions = rowActionsService.actions();
|
||||
init = rowActionsService.init;
|
||||
var loadbalancerService = $injector.get(
|
||||
'horizon.dashboard.project.lbaasv2.loadbalancers.service');
|
||||
spyOn(loadbalancerService, 'isActive').and.callFake(isActiveMock);
|
||||
}));
|
||||
|
||||
it('should define correct table row actions', function() {
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0].template.text).toBe('Edit');
|
||||
});
|
||||
|
||||
it('should allow editing a listener of an ACTIVE load balancer', function() {
|
||||
init('active');
|
||||
expect(canEdit({listenerId: '1234'})).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow editing a listener of a non-ACTIVE load balancer', function() {
|
||||
init('non-active');
|
||||
expect(canEdit({listenerId: '1234'})).toBe(false);
|
||||
});
|
||||
|
||||
it('should have the "allowed" and "perform" functions', function() {
|
||||
actions.forEach(function(action) {
|
||||
expect(action.service.allowed).toBeDefined();
|
||||
expect(action.service.perform).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reload table after edit', function() {
|
||||
spyOn($route, 'reload').and.callThrough();
|
||||
actions[0].service.perform();
|
||||
expect($route.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
})();
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
ListenerDetailController.$inject = [
|
||||
'horizon.app.core.openstack-service-api.lbaasv2',
|
||||
'horizon.dashboard.project.lbaasv2.listeners.actions.rowActions',
|
||||
'$routeParams'
|
||||
];
|
||||
|
||||
|
@ -33,13 +34,16 @@
|
|||
* Controller for the LBaaS v2 listener detail page.
|
||||
*
|
||||
* @param api The LBaaS v2 API service.
|
||||
* @param rowActions The listener row actions service.
|
||||
* @param $routeParams The angular $routeParams service.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function ListenerDetailController(api, $routeParams) {
|
||||
function ListenerDetailController(api, rowActions, $routeParams) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.actions = rowActions.actions;
|
||||
|
||||
init();
|
||||
|
||||
////////////////////////////////
|
||||
|
|
|
@ -29,12 +29,16 @@
|
|||
|
||||
///////////////////////
|
||||
|
||||
beforeEach(module('horizon.framework.util.http'));
|
||||
beforeEach(module('horizon.framework.util'));
|
||||
beforeEach(module('horizon.framework.widgets.toast'));
|
||||
beforeEach(module('horizon.framework.conf'));
|
||||
beforeEach(module('horizon.app.core.openstack-service-api'));
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('$modal', {});
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
|
||||
spyOn(lbaasv2API, 'getListener').and.callFake(fakeAPI);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<p ng-if="::ctrl.listener.description">{$ ::ctrl.listener.description $}</p>
|
||||
</div>
|
||||
<div class="detail-page">
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.listener" ng-if="ctrl.listener" class="pull-right"></actions>
|
||||
<dl class="dl-horizontal">
|
||||
<div>
|
||||
<dt translate>Listener ID</dt>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
ListenersTableController.$inject = [
|
||||
'horizon.app.core.openstack-service-api.lbaasv2',
|
||||
'$routeParams',
|
||||
'horizon.dashboard.project.lbaasv2.loadbalancers.actions.batchActions'
|
||||
'horizon.dashboard.project.lbaasv2.listeners.actions.rowActions'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -35,18 +35,18 @@
|
|||
*
|
||||
* @param api The LBaaS V2 service API.
|
||||
* @param $routeParams The angular $routeParams service.
|
||||
* @param batchActions The load balancer batch actions service.
|
||||
* @param rowActions The listener row actions service.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function ListenersTableController(api, $routeParams, batchActions) {
|
||||
function ListenersTableController(api, $routeParams, rowActions) {
|
||||
|
||||
var ctrl = this;
|
||||
ctrl.items = [];
|
||||
ctrl.src = [];
|
||||
ctrl.checked = {};
|
||||
ctrl.batchActions = batchActions;
|
||||
ctrl.loadbalancerId = $routeParams.loadbalancerId;
|
||||
ctrl.rowActions = rowActions.init(ctrl.loadbalancerId);
|
||||
|
||||
init();
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Listeners Table Controller', function() {
|
||||
var controller, lbaasv2API;
|
||||
var controller, lbaasv2API, rowActions;
|
||||
var items = [];
|
||||
|
||||
function fakeAPI() {
|
||||
|
@ -28,6 +28,10 @@
|
|||
};
|
||||
}
|
||||
|
||||
function initMock() {
|
||||
return rowActions;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
beforeEach(module('horizon.framework.widgets.toast'));
|
||||
|
@ -43,6 +47,8 @@
|
|||
beforeEach(inject(function($injector) {
|
||||
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
|
||||
controller = $injector.get('$controller');
|
||||
rowActions = $injector.get('horizon.dashboard.project.lbaasv2.listeners.actions.rowActions');
|
||||
spyOn(rowActions, 'init').and.callFake(initMock);
|
||||
spyOn(lbaasv2API, 'getListeners').and.callFake(fakeAPI);
|
||||
}));
|
||||
|
||||
|
@ -57,7 +63,9 @@
|
|||
expect(ctrl.items).toEqual([]);
|
||||
expect(ctrl.src).toEqual(items);
|
||||
expect(ctrl.checked).toEqual({});
|
||||
expect(ctrl.batchActions).toBeDefined();
|
||||
expect(ctrl.loadbalancerId).toEqual('1234');
|
||||
expect(rowActions.init).toHaveBeenCalledWith(ctrl.loadbalancerId);
|
||||
expect(ctrl.rowActions).toEqual(rowActions);
|
||||
});
|
||||
|
||||
it('should invoke lbaasv2 apis', function() {
|
||||
|
@ -65,5 +73,10 @@
|
|||
expect(lbaasv2API.getListeners).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should init the rowactions', function() {
|
||||
createController();
|
||||
expect(lbaasv2API.getListeners).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -70,6 +70,13 @@
|
|||
<td class="rsp-p1">{$ ::item.description | noValue $}</td>
|
||||
<td class="rsp-p1">{$ ::item.protocol$}</td>
|
||||
<td class="rsp-p1">{$ ::item.protocol_port$}</td>
|
||||
<td class="action-col">
|
||||
<!--
|
||||
Table-row-action-column:
|
||||
Actions taken here apply to a single item/row.
|
||||
-->
|
||||
<actions allowed="table.rowActions.actions" type="row" item="item"></actions>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-repeat-end class="detail-row">
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
<select class="form-control input-sm" name="listener-protocol"
|
||||
id="listener-protocol"
|
||||
ng-options="protocol for protocol in model.listenerProtocols"
|
||||
ng-model="model.spec.listener.protocol" ng-required="model.context.resource === 'listener'">
|
||||
ng-model="model.spec.listener.protocol" ng-required="model.context.resource === 'listener'"
|
||||
ng-disabled="model.context.id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -52,7 +53,8 @@
|
|||
<input name="listener-port" id="listener-port"
|
||||
type="number" class="form-control input-sm"
|
||||
ng-model="model.spec.listener.port" ng-pattern="/^\d+$/" min="1" max="65535"
|
||||
ng-required="model.context.resource === 'listener'">
|
||||
ng-required="model.context.resource === 'listener'"
|
||||
ng-disabled="model.context.id">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<input name="loadbalancer-ip" id="loadbalancer-ip"
|
||||
type="text" class="form-control input-sm"
|
||||
ng-model="model.spec.loadbalancer.ip" ng-pattern="::ctrl.ipPattern"
|
||||
ng-disabled="model.context.resource === 'loadbalancer' && model.context.id">
|
||||
ng-disabled="model.context.id">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
|||
id="loadbalancer-subnet"
|
||||
ng-options="subnet.name for subnet in model.subnets"
|
||||
ng-model="model.spec.loadbalancer.subnet" ng-required="true"
|
||||
ng-disabled="model.context.resource === 'loadbalancer' && model.context.id">
|
||||
ng-disabled="model.context.id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
ng-class="{ 'has-error': memberDetailsForm['{$ ::row.id $}-address'].$invalid && memberDetailsForm['{$ ::row.id $}-address'].$dirty }">
|
||||
<input name="{$ ::row.id $}-address" type="text" class="form-control input-sm"
|
||||
ng-model="row.address" ng-pattern="::ctrl.ipPattern"
|
||||
ng-required="true">
|
||||
ng-required="true"
|
||||
ng-disabled="model.context.id && row.allocatedMember">
|
||||
</div>
|
||||
<span ng-if="!row.addresses"
|
||||
class="fa fa-exclamation-triangle invalid"
|
||||
|
@ -69,7 +70,8 @@
|
|||
class="form-field">
|
||||
<select name="{$ ::row.id $}-subnet" class="form-control input-sm"
|
||||
ng-options="subnet.name for subnet in model.subnets"
|
||||
ng-model="row.subnet">
|
||||
ng-model="row.subnet"
|
||||
ng-disabled="model.context.id && row.allocatedMember">
|
||||
</select>
|
||||
</div>
|
||||
<span ng-if="row.addresses">{$ ctrl.getSubnetName(row) $}</span>
|
||||
|
@ -79,7 +81,8 @@
|
|||
ng-class="{ 'has-error': memberDetailsForm['{$ ::row.id $}-port'].$invalid && memberDetailsForm['{$ ::row.id $}-port'].$dirty }">
|
||||
<input name="{$ ::row.id $}-port" type="number" class="form-control input-sm"
|
||||
ng-model="row.port" ng-pattern="/^\d+$/" min="1" max="65535"
|
||||
ng-required="true">
|
||||
ng-required="true"
|
||||
ng-disabled="model.context.id && row.allocatedMember">
|
||||
</div>
|
||||
<span class="fa fa-exclamation-triangle invalid"
|
||||
ng-show="memberDetailsForm['{$ ::row.id $}-port'].$invalid && memberDetailsForm.$dirty"
|
||||
|
@ -91,7 +94,8 @@
|
|||
<div class="form-field member-weight"
|
||||
ng-class="{ 'has-error': memberDetailsForm['{$ ::row.id $}-weight'].$invalid && memberDetailsForm['{$ ::row.id $}-weight'].$dirty }">
|
||||
<input name="{$ ::row.id $}-weight" type="number" class="form-control input-sm"
|
||||
ng-model="row.weight" ng-pattern="/^\d+$/" min="1" max="256">
|
||||
ng-model="row.weight" ng-pattern="/^\d+$/" min="1" max="256"
|
||||
ng-disabled="model.context.id && row.allocatedMember">
|
||||
</div>
|
||||
<span class="fa fa-exclamation-triangle invalid"
|
||||
ng-show="memberDetailsForm['{$ ::row.id $}-weight'].$invalid && memberDetailsForm.$dirty"
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
*/
|
||||
|
||||
function workflowModel($q, neutronAPI, novaAPI, lbaasv2API, gettext) {
|
||||
var initPromise, ports;
|
||||
var ports;
|
||||
|
||||
/**
|
||||
* @ngdoc model api object
|
||||
|
@ -70,6 +70,7 @@
|
|||
|
||||
spec: null,
|
||||
|
||||
visibleResources: [],
|
||||
subnets: [],
|
||||
members: [],
|
||||
listenerProtocols: ['TCP', 'HTTP', 'HTTPS'],
|
||||
|
@ -86,6 +87,8 @@
|
|||
submit: submit
|
||||
};
|
||||
|
||||
return model;
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name workflowModel.initialize
|
||||
|
@ -108,7 +111,10 @@
|
|||
submit: null
|
||||
};
|
||||
|
||||
model.visibleResources = [];
|
||||
|
||||
model.spec = {
|
||||
loadbalancer_id: null,
|
||||
loadbalancer: {
|
||||
name: null,
|
||||
description: null,
|
||||
|
@ -116,18 +122,21 @@
|
|||
subnet: null
|
||||
},
|
||||
listener: {
|
||||
id: null,
|
||||
name: gettext('Listener 1'),
|
||||
description: null,
|
||||
protocol: null,
|
||||
port: null
|
||||
},
|
||||
pool: {
|
||||
id: null,
|
||||
name: gettext('Pool 1'),
|
||||
description: null,
|
||||
protocol: null,
|
||||
method: null
|
||||
},
|
||||
monitor: {
|
||||
id: null,
|
||||
type: null,
|
||||
interval: null,
|
||||
retry: null,
|
||||
|
@ -140,35 +149,40 @@
|
|||
};
|
||||
|
||||
if (model.initializing) {
|
||||
promise = initPromise;
|
||||
} else {
|
||||
model.initializing = true;
|
||||
return promise;
|
||||
}
|
||||
model.initializing = true;
|
||||
|
||||
switch ((id ? 'edit' : 'create') + resource) {
|
||||
case 'createloadbalancer':
|
||||
promise = $q.all([
|
||||
lbaasv2API.getLoadBalancers().then(onGetLoadBalancers),
|
||||
neutronAPI.getSubnets().then(onGetSubnets),
|
||||
neutronAPI.getPorts().then(onGetPorts),
|
||||
novaAPI.getServers().then(onGetServers)
|
||||
]).then(initMemberAddresses);
|
||||
model.context.submit = createLoadBalancer;
|
||||
break;
|
||||
case 'editloadbalancer':
|
||||
promise = $q.all([
|
||||
lbaasv2API.getLoadBalancer(model.context.id).then(onGetLoadBalancer),
|
||||
neutronAPI.getSubnets().then(onGetSubnets)
|
||||
]).then(initSubnet);
|
||||
model.context.submit = editLoadBalancer;
|
||||
break;
|
||||
default:
|
||||
throw Error('Invalid resource context: ' + (id ? 'edit' : 'create') + resource);
|
||||
}
|
||||
|
||||
promise.then(onInitSuccess, onInitFail);
|
||||
switch ((id ? 'edit' : 'create') + resource) {
|
||||
case 'createloadbalancer':
|
||||
promise = $q.all([
|
||||
lbaasv2API.getLoadBalancers().then(onGetLoadBalancers),
|
||||
neutronAPI.getSubnets().then(onGetSubnets),
|
||||
neutronAPI.getPorts().then(onGetPorts),
|
||||
novaAPI.getServers().then(onGetServers)
|
||||
]).then(initMemberAddresses);
|
||||
model.context.submit = createLoadBalancer;
|
||||
break;
|
||||
case 'editloadbalancer':
|
||||
promise = $q.all([
|
||||
lbaasv2API.getLoadBalancer(model.context.id).then(onGetLoadBalancer),
|
||||
neutronAPI.getSubnets().then(onGetSubnets)
|
||||
]).then(initSubnet);
|
||||
model.context.submit = editLoadBalancer;
|
||||
break;
|
||||
case 'editlistener':
|
||||
promise = $q.all([
|
||||
neutronAPI.getSubnets().then(onGetSubnets).then(getListener).then(onGetListener),
|
||||
neutronAPI.getPorts().then(onGetPorts),
|
||||
novaAPI.getServers().then(onGetServers)
|
||||
]).then(initMemberAddresses);
|
||||
model.context.submit = editListener;
|
||||
break;
|
||||
default:
|
||||
throw Error('Invalid resource context: ' + (id ? 'edit' : 'create') + resource);
|
||||
}
|
||||
|
||||
return promise;
|
||||
return promise.then(onInitSuccess, onInitFail);
|
||||
}
|
||||
|
||||
function onInitSuccess() {
|
||||
|
@ -211,6 +225,10 @@
|
|||
return lbaasv2API.editLoadBalancer(model.context.id, spec);
|
||||
}
|
||||
|
||||
function editListener(spec) {
|
||||
return lbaasv2API.editListener(model.context.id, spec);
|
||||
}
|
||||
|
||||
function cleanFinalSpecLoadBalancer(finalSpec) {
|
||||
var context = model.context;
|
||||
|
||||
|
@ -259,7 +277,8 @@
|
|||
var members = [];
|
||||
angular.forEach(finalSpec.members, function cleanMember(member) {
|
||||
if (member.address && member.port) {
|
||||
['id', 'name', 'description', 'addresses'].forEach(function deleteProperty(prop) {
|
||||
['name', 'description', 'addresses', 'allocatedMember'].forEach(
|
||||
function deleteProperty(prop) {
|
||||
if (angular.isDefined(member[prop])) {
|
||||
delete member[prop];
|
||||
}
|
||||
|
@ -362,18 +381,101 @@
|
|||
});
|
||||
});
|
||||
member.address = member.addresses[0];
|
||||
|
||||
if (model.spec.pool.protocol) {
|
||||
member.port = {'HTTP': 80}[model.spec.pool.protocol];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getListener() {
|
||||
return lbaasv2API.getListener(model.context.id, true);
|
||||
}
|
||||
|
||||
function onGetLoadBalancer(response) {
|
||||
var loadbalancer = response.data;
|
||||
setLoadBalancerSpec(loadbalancer);
|
||||
model.visibleResources.push('loadbalancer');
|
||||
}
|
||||
|
||||
function onGetListener(response) {
|
||||
var resources = response.data;
|
||||
|
||||
setListenerSpec(resources.listener);
|
||||
model.visibleResources.push('listener');
|
||||
model.spec.loadbalancer_id = resources.listener.loadbalancers[0].id;
|
||||
|
||||
if (resources.pool) {
|
||||
setPoolSpec(resources.pool);
|
||||
model.visibleResources.push('pool');
|
||||
model.visibleResources.push('members');
|
||||
|
||||
if (resources.members) {
|
||||
setMembersSpec(resources.members);
|
||||
}
|
||||
|
||||
if (resources.monitor) {
|
||||
setMonitorSpec(resources.monitor);
|
||||
model.visibleResources.push('monitor');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setLoadBalancerSpec(loadbalancer) {
|
||||
var spec = model.spec.loadbalancer;
|
||||
spec.name = loadbalancer.name || '';
|
||||
spec.description = loadbalancer.description || '';
|
||||
spec.ip = loadbalancer.vip_address || '';
|
||||
spec.name = loadbalancer.name;
|
||||
spec.description = loadbalancer.description;
|
||||
spec.ip = loadbalancer.vip_address;
|
||||
spec.subnet = loadbalancer.vip_subnet_id;
|
||||
}
|
||||
|
||||
function setListenerSpec(listener) {
|
||||
var spec = model.spec.listener;
|
||||
spec.id = listener.id;
|
||||
spec.name = listener.name;
|
||||
spec.description = listener.description;
|
||||
spec.protocol = listener.protocol;
|
||||
spec.port = listener.protocol_port;
|
||||
}
|
||||
|
||||
function setPoolSpec(pool) {
|
||||
var spec = model.spec.pool;
|
||||
spec.id = pool.id;
|
||||
spec.name = pool.name;
|
||||
spec.description = pool.description;
|
||||
spec.protocol = pool.protocol;
|
||||
spec.method = pool.lb_algorithm;
|
||||
}
|
||||
|
||||
function setMembersSpec(membersList) {
|
||||
model.spec.members.length = 0;
|
||||
var members = [];
|
||||
|
||||
angular.forEach(membersList, function addMember(member) {
|
||||
members.push({
|
||||
id: member.id,
|
||||
address: member.address,
|
||||
subnet: mapSubnetObj(member.subnet_id),
|
||||
port: member.protocol_port,
|
||||
weight: member.weight,
|
||||
allocatedMember: true
|
||||
});
|
||||
});
|
||||
push.apply(model.spec.members, members);
|
||||
}
|
||||
|
||||
function setMonitorSpec(monitor) {
|
||||
var spec = model.spec.monitor;
|
||||
spec.id = monitor.id;
|
||||
spec.type = monitor.type;
|
||||
spec.interval = monitor.delay;
|
||||
spec.timeout = monitor.timeout;
|
||||
spec.retry = monitor.max_retries;
|
||||
spec.method = monitor.http_method;
|
||||
spec.status = monitor.expected_codes;
|
||||
spec.path = monitor.url_path;
|
||||
}
|
||||
|
||||
function initSubnet() {
|
||||
var subnet = model.subnets.filter(function filterSubnetsByLoadBalancer(s) {
|
||||
return s.id === model.spec.loadbalancer.subnet;
|
||||
|
@ -381,7 +483,13 @@
|
|||
model.spec.loadbalancer.subnet = subnet;
|
||||
}
|
||||
|
||||
return model;
|
||||
function mapSubnetObj(subnetId) {
|
||||
var subnet = model.subnets.filter(function mapSubnet(subnet) {
|
||||
return subnet.id === subnetId;
|
||||
});
|
||||
|
||||
return subnet[0];
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -17,15 +17,64 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Workflow Model Service', function() {
|
||||
var model, $q, scope;
|
||||
var model, $q, scope, listenerResources;
|
||||
|
||||
beforeEach(module('horizon.framework.util.i18n'));
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(function() {
|
||||
listenerResources = {
|
||||
listener: {
|
||||
id: '1234',
|
||||
name: 'Listener 1',
|
||||
description: 'listener description',
|
||||
protocol: 'HTTP',
|
||||
protocol_port: 80,
|
||||
loadbalancers: [ { id: '1234' } ]
|
||||
},
|
||||
pool: {
|
||||
id: '1234',
|
||||
name: 'Pool 1',
|
||||
protocol: 'HTTP',
|
||||
lb_algorithm: 'ROUND_ROBIN',
|
||||
description: 'pool description'
|
||||
},
|
||||
members: [
|
||||
{
|
||||
id: '1234',
|
||||
address: '1.2.3.4',
|
||||
subnet_id: 'subnet-1',
|
||||
protocol_port: 80,
|
||||
weight: 1
|
||||
},
|
||||
{
|
||||
id: '5678',
|
||||
address: '5.6.7.8',
|
||||
subnet_id: 'subnet-1',
|
||||
protocol_port: 80,
|
||||
weight: 1
|
||||
}
|
||||
],
|
||||
monitor: {
|
||||
id: '1234',
|
||||
type: 'HTTP',
|
||||
delay: 1,
|
||||
timeout: 1,
|
||||
max_retries: 1,
|
||||
http_method: 'POST',
|
||||
expected_codes: '200',
|
||||
url_path: '/test'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('horizon.app.core.openstack-service-api.lbaasv2', {
|
||||
getLoadBalancers: function() {
|
||||
var loadbalancers = [ { name: 'Load Balancer 1' }, { name: 'Load Balancer 2' } ];
|
||||
var loadbalancers = [
|
||||
{ id: '1234', name: 'Load Balancer 1' },
|
||||
{ id: '5678', name: 'Load Balancer 2' }
|
||||
];
|
||||
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: { items: loadbalancers } });
|
||||
|
@ -33,10 +82,74 @@
|
|||
return deferred.promise;
|
||||
},
|
||||
getLoadBalancer: function() {
|
||||
var loadbalancer = { vip_subnet_id: 'subnet-1' };
|
||||
var loadbalancer = {
|
||||
id: '1234',
|
||||
name: 'Load Balancer 1',
|
||||
vip_address: '1.2.3.4',
|
||||
vip_subnet_id: 'subnet-1',
|
||||
description: ''
|
||||
};
|
||||
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: loadbalancer });
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
getListener: function() {
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: listenerResources });
|
||||
return deferred.promise;
|
||||
},
|
||||
getPool: function() {
|
||||
var pool = {
|
||||
id: '1234',
|
||||
name: 'Pool 1',
|
||||
protocol: 'HTTP',
|
||||
lb_algorithm: 'ROUND_ROBIN',
|
||||
description: 'pool description'
|
||||
};
|
||||
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: loadbalancer });
|
||||
deferred.resolve({ data: pool });
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
getMembers: function() {
|
||||
var members = [
|
||||
{
|
||||
id: '1234',
|
||||
address: '1.2.3.4',
|
||||
subnet_id: 'subnet-1',
|
||||
protocol_port: 80,
|
||||
weight: 1
|
||||
},
|
||||
{
|
||||
id: '5678',
|
||||
address: '5.6.7.8',
|
||||
subnet_id: 'subnet-1',
|
||||
protocol_port: 80,
|
||||
weight: 1
|
||||
}];
|
||||
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: { items: members } });
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
getHealthMonitor: function() {
|
||||
var monitor = {
|
||||
id: '1234',
|
||||
type: 'HTTP',
|
||||
delay: 1,
|
||||
timeout: 1,
|
||||
max_retries: 1,
|
||||
http_method: 'POST',
|
||||
expected_codes: '200',
|
||||
url_path: '/test'
|
||||
};
|
||||
|
||||
var deferred = $q.defer();
|
||||
deferred.resolve({ data: monitor });
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
@ -45,6 +158,9 @@
|
|||
},
|
||||
editLoadBalancer: function(id, spec) {
|
||||
return spec;
|
||||
},
|
||||
editListener: function(id, spec) {
|
||||
return spec;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -94,7 +210,7 @@
|
|||
scope = $injector.get('$rootScope').$new();
|
||||
}));
|
||||
|
||||
describe('Initial object (pre-initialize)', function() {
|
||||
describe('Initial model (pre-initialize)', function() {
|
||||
|
||||
it('is defined', function() {
|
||||
expect(model).toBeDefined();
|
||||
|
@ -150,7 +266,7 @@
|
|||
});
|
||||
});
|
||||
|
||||
describe('Post initialize model', function() {
|
||||
describe('Post initialize model (create loadbalancer)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('loadbalancer');
|
||||
|
@ -163,6 +279,7 @@
|
|||
expect(model.subnets.length).toBe(2);
|
||||
expect(model.members.length).toBe(2);
|
||||
expect(model.spec).toBeDefined();
|
||||
expect(model.spec.loadbalancer_id).toBeNull();
|
||||
expect(model.spec.loadbalancer).toBeDefined();
|
||||
expect(model.spec.listener).toBeDefined();
|
||||
expect(model.spec.pool).toBeDefined();
|
||||
|
@ -176,19 +293,269 @@
|
|||
expect(model.spec.pool.name).toBe('Pool 1');
|
||||
});
|
||||
|
||||
it('should initialize monitor fields', function() {
|
||||
it('should initialize context properties', function() {
|
||||
expect(model.context.resource).toBe('loadbalancer');
|
||||
expect(model.context.id).toBeUndefined();
|
||||
expect(model.context.submit).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Post initialize model (edit loadbalancer)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('loadbalancer', '1234');
|
||||
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).toEqual([]);
|
||||
expect(model.spec).toBeDefined();
|
||||
expect(model.spec.loadbalancer_id).toBeNull();
|
||||
expect(model.spec.loadbalancer).toBeDefined();
|
||||
expect(model.spec.listener).toBeDefined();
|
||||
expect(model.spec.pool).toBeDefined();
|
||||
expect(model.spec.members).toEqual([]);
|
||||
expect(model.spec.monitor).toBeDefined();
|
||||
});
|
||||
|
||||
it('should initialize loadbalancer model spec properties', function() {
|
||||
expect(model.spec.loadbalancer.name).toEqual('Load Balancer 1');
|
||||
expect(model.spec.loadbalancer.description).toEqual('');
|
||||
expect(model.spec.loadbalancer.ip).toEqual('1.2.3.4');
|
||||
expect(model.spec.loadbalancer.subnet).toEqual({ id: 'subnet-1', name: 'subnet-1' });
|
||||
});
|
||||
|
||||
it('should not initialize listener model spec properties', function() {
|
||||
expect(model.spec.listener.id).toBeNull();
|
||||
expect(model.spec.listener.name).toBe('Listener 1');
|
||||
expect(model.spec.listener.description).toBeNull();
|
||||
expect(model.spec.listener.protocol).toBeNull();
|
||||
expect(model.spec.listener.port).toBeNull();
|
||||
});
|
||||
|
||||
it('should not initialize pool model spec properties', function() {
|
||||
expect(model.spec.pool.id).toBeNull();
|
||||
expect(model.spec.pool.name).toBe('Pool 1');
|
||||
expect(model.spec.pool.description).toBeNull();
|
||||
expect(model.spec.pool.protocol).toBeNull();
|
||||
expect(model.spec.pool.method).toBeNull();
|
||||
});
|
||||
|
||||
it('should initialize monitor model spec properties to null', function() {
|
||||
expect(model.spec.monitor.type).toBeNull();
|
||||
expect(model.spec.monitor.interval).toBeNull();
|
||||
expect(model.spec.monitor.retry).toBeNull();
|
||||
expect(model.spec.monitor.timeout).toBeNull();
|
||||
expect(model.spec.monitor.method).toBe('GET');
|
||||
expect(model.spec.monitor.status).toBe('200');
|
||||
expect(model.spec.monitor.path).toBe('/');
|
||||
});
|
||||
|
||||
it('should not initialize any members in the model spec', function() {
|
||||
expect(model.spec.members).toEqual([]);
|
||||
});
|
||||
|
||||
it('should initialize context', function() {
|
||||
expect(model.context.resource).toBe('loadbalancer');
|
||||
expect(model.context.id).toBeUndefined();
|
||||
expect(model.context.id).toBe('1234');
|
||||
expect(model.context.submit).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Post initialize model (edit listener)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('listener', '1234');
|
||||
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).toEqual(2);
|
||||
expect(model.spec).toBeDefined();
|
||||
expect(model.spec.loadbalancer_id).toBeDefined();
|
||||
expect(model.spec.loadbalancer).toBeDefined();
|
||||
expect(model.spec.listener).toBeDefined();
|
||||
expect(model.spec.pool).toBeDefined();
|
||||
expect(model.subnets.length).toBe(2);
|
||||
expect(model.spec.monitor).toBeDefined();
|
||||
});
|
||||
|
||||
it('should initialize the loadbalancer_id property', function() {
|
||||
expect(model.spec.loadbalancer_id).toBe('1234');
|
||||
});
|
||||
|
||||
it('should initialize all loadbalancer properties to null', function() {
|
||||
expect(model.spec.loadbalancer.name).toBeNull();
|
||||
expect(model.spec.loadbalancer.description).toBeNull();
|
||||
expect(model.spec.loadbalancer.ip).toBeNull();
|
||||
expect(model.spec.loadbalancer.subnet).toBeNull();
|
||||
});
|
||||
|
||||
it('should initialize all listener properties', function() {
|
||||
expect(model.spec.listener.id).toBe('1234');
|
||||
expect(model.spec.listener.name).toBe('Listener 1');
|
||||
expect(model.spec.listener.description).toBe('listener description');
|
||||
expect(model.spec.listener.protocol).toBe('HTTP');
|
||||
expect(model.spec.listener.port).toBe(80);
|
||||
});
|
||||
|
||||
it('should initialize all pool properties', function() {
|
||||
expect(model.spec.pool.id).toBe('1234');
|
||||
expect(model.spec.pool.name).toBe('Pool 1');
|
||||
expect(model.spec.pool.description).toBe('pool description');
|
||||
expect(model.spec.pool.protocol).toBe('HTTP');
|
||||
expect(model.spec.pool.method).toBe('ROUND_ROBIN');
|
||||
});
|
||||
|
||||
it('should initialize all monitor properties', function() {
|
||||
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.retry).toBe(1);
|
||||
expect(model.spec.monitor.timeout).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 members and properties', function() {
|
||||
expect(model.spec.members[0].id).toBe('1234');
|
||||
expect(model.spec.members[0].address).toBe('1.2.3.4');
|
||||
expect(model.spec.members[0].subnet).toEqual({ id: 'subnet-1', name: 'subnet-1' });
|
||||
expect(model.spec.members[0].port).toBe(80);
|
||||
expect(model.spec.members[0].weight).toBe(1);
|
||||
expect(model.spec.members[1].id).toBe('5678');
|
||||
expect(model.spec.members[1].address).toBe('5.6.7.8');
|
||||
expect(model.spec.members[1].subnet).toEqual({ id: 'subnet-1', name: 'subnet-1' });
|
||||
expect(model.spec.members[1].port).toBe(80);
|
||||
expect(model.spec.members[1].weight).toBe(1);
|
||||
});
|
||||
|
||||
it('should initialize context', function() {
|
||||
expect(model.context.resource).toBe('listener');
|
||||
expect(model.context.id).toBeDefined();
|
||||
expect(model.context.submit).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Post initialize model - Initializing', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initializing = true;
|
||||
model.initialize('loadbalancer');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
// 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(6);
|
||||
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);
|
||||
expect(Object.keys(model.spec.monitor).length).toBe(8);
|
||||
expect(model.spec.members).toEqual([]);
|
||||
});
|
||||
|
||||
it('sets load balancer ID to null', function() {
|
||||
expect(model.spec.loadbalancer_id).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer name to null', function() {
|
||||
expect(model.spec.loadbalancer.name).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer description to null', function() {
|
||||
expect(model.spec.loadbalancer.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer ip address to null', function() {
|
||||
expect(model.spec.loadbalancer.ip).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer subnet to null', function() {
|
||||
expect(model.spec.loadbalancer.subnet).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener id to null', function() {
|
||||
expect(model.spec.listener.id).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener name to reasonable default', function() {
|
||||
expect(model.spec.listener.name).toBe('Listener 1');
|
||||
});
|
||||
|
||||
it('sets listener description to null', function() {
|
||||
expect(model.spec.listener.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener protocol to null', function() {
|
||||
expect(model.spec.listener.protocol).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener port to null', function() {
|
||||
expect(model.spec.listener.port).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool id to null', function() {
|
||||
expect(model.spec.pool.id).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool name to reasonable default', function() {
|
||||
expect(model.spec.pool.name).toBe('Pool 1');
|
||||
});
|
||||
|
||||
it('sets pool description to null', function() {
|
||||
expect(model.spec.pool.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool protocol to null', function() {
|
||||
expect(model.spec.pool.protocol).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool method to null', function() {
|
||||
expect(model.spec.pool.method).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor id to null', function() {
|
||||
expect(model.spec.monitor.id).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor type to null', function() {
|
||||
expect(model.spec.monitor.type).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor interval to null', function() {
|
||||
expect(model.spec.monitor.interval).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor retry count to null', function() {
|
||||
expect(model.spec.monitor.retry).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor timeout to null', function() {
|
||||
expect(model.spec.monitor.timeout).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor method to default', function() {
|
||||
expect(model.spec.monitor.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('sets monitor status code to default', function() {
|
||||
expect(model.spec.monitor.status).toBe('200');
|
||||
});
|
||||
|
||||
it('sets monitor URL path to default', function() {
|
||||
expect(model.spec.monitor.path).toBe('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Initialization failure', function() {
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
|
@ -231,101 +598,6 @@
|
|||
});
|
||||
});
|
||||
|
||||
describe('Post initialize model - Initializing', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initializing = true;
|
||||
model.initialize('loadbalancer');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
// 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(5);
|
||||
expect(Object.keys(model.spec.loadbalancer).length).toBe(4);
|
||||
expect(Object.keys(model.spec.listener).length).toBe(4);
|
||||
expect(Object.keys(model.spec.pool).length).toBe(4);
|
||||
expect(Object.keys(model.spec.monitor).length).toBe(7);
|
||||
});
|
||||
|
||||
it('sets load balancer name to null', function() {
|
||||
expect(model.spec.loadbalancer.name).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer description to null', function() {
|
||||
expect(model.spec.loadbalancer.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer ip address to null', function() {
|
||||
expect(model.spec.loadbalancer.ip).toBeNull();
|
||||
});
|
||||
|
||||
it('sets load balancer subnet to null', function() {
|
||||
expect(model.spec.loadbalancer.subnet).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener name to reasonable default', function() {
|
||||
expect(model.spec.listener.name).toBe('Listener 1');
|
||||
});
|
||||
|
||||
it('sets listener description to null', function() {
|
||||
expect(model.spec.listener.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener protocol to null', function() {
|
||||
expect(model.spec.listener.protocol).toBeNull();
|
||||
});
|
||||
|
||||
it('sets listener port to null', function() {
|
||||
expect(model.spec.listener.port).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool name to reasonable default', function() {
|
||||
expect(model.spec.pool.name).toBe('Pool 1');
|
||||
});
|
||||
|
||||
it('sets pool description to null', function() {
|
||||
expect(model.spec.pool.description).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool protocol to null', function() {
|
||||
expect(model.spec.pool.protocol).toBeNull();
|
||||
});
|
||||
|
||||
it('sets pool method to null', function() {
|
||||
expect(model.spec.pool.method).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor type to null', function() {
|
||||
expect(model.spec.monitor.type).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor interval to null', function() {
|
||||
expect(model.spec.monitor.interval).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor retry count to null', function() {
|
||||
expect(model.spec.monitor.retry).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor timeout to null', function() {
|
||||
expect(model.spec.monitor.timeout).toBeNull();
|
||||
});
|
||||
|
||||
it('sets monitor method to default', function() {
|
||||
expect(model.spec.monitor.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('sets monitor status code to default', function() {
|
||||
expect(model.spec.monitor.status).toBe('200');
|
||||
});
|
||||
|
||||
it('sets monitor URL path to default', function() {
|
||||
expect(model.spec.monitor.path).toBe('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('context (create loadbalancer)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -354,6 +626,20 @@
|
|||
});
|
||||
});
|
||||
|
||||
describe('context (edit listener)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('listener', '1');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
it('should initialize context', function() {
|
||||
expect(model.context.resource).toBe('listener');
|
||||
expect(model.context.id).toBe('1');
|
||||
expect(model.context.submit.name).toBe('editListener');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model submit function (create loadbalancer)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -409,32 +695,39 @@
|
|||
expect(finalSpec.loadbalancer.description).toBeUndefined();
|
||||
expect(finalSpec.loadbalancer.ip).toBe('1.2.3.4');
|
||||
expect(finalSpec.loadbalancer.subnet).toBe(model.subnets[0].id);
|
||||
|
||||
expect(finalSpec.listener.name).toBe('Listener 1');
|
||||
expect(finalSpec.listener.description).toBeUndefined();
|
||||
expect(finalSpec.listener.protocol).toBe('HTTPS');
|
||||
expect(finalSpec.listener.port).toBe(80);
|
||||
|
||||
expect(finalSpec.pool.name).toBe('pool name');
|
||||
expect(finalSpec.pool.description).toBe('pool description');
|
||||
expect(finalSpec.pool.protocol).toBe('HTTP');
|
||||
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].id).toBeUndefined();
|
||||
expect(finalSpec.members[0].name).toBeUndefined();
|
||||
expect(finalSpec.members[1].id).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[2].id).toBeUndefined();
|
||||
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);
|
||||
|
@ -535,7 +828,7 @@
|
|||
describe('Model submit function (edit loadbalancer)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('loadbalancer', '1');
|
||||
model.initialize('loadbalancer', '1234');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
|
@ -544,12 +837,80 @@
|
|||
|
||||
var finalSpec = model.submit();
|
||||
|
||||
expect(finalSpec.loadbalancer.name).toBe('');
|
||||
expect(finalSpec.loadbalancer.name).toBe('Load Balancer 1');
|
||||
expect(finalSpec.loadbalancer.description).toBe('new description');
|
||||
expect(finalSpec.loadbalancer.ip).toBe('');
|
||||
expect(finalSpec.loadbalancer.ip).toBe('1.2.3.4');
|
||||
expect(finalSpec.loadbalancer.subnet).toBe('subnet-1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model submit function (edit listener)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
model.initialize('listener', '1234');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
it('should set final spec properties', function() {
|
||||
var finalSpec = model.submit();
|
||||
|
||||
expect(finalSpec.loadbalancer).toBeUndefined();
|
||||
|
||||
expect(finalSpec.listener.name).toBe('Listener 1');
|
||||
expect(finalSpec.listener.description).toBe('listener description');
|
||||
expect(finalSpec.listener.protocol).toBe('HTTP');
|
||||
expect(finalSpec.listener.port).toBe(80);
|
||||
|
||||
expect(finalSpec.pool.name).toBe('Pool 1');
|
||||
expect(finalSpec.pool.description).toBe('pool description');
|
||||
expect(finalSpec.pool.protocol).toBe('HTTP');
|
||||
expect(finalSpec.pool.method).toBe('ROUND_ROBIN');
|
||||
|
||||
expect(finalSpec.members.length).toBe(2);
|
||||
expect(finalSpec.members[0].id).toBe('1234');
|
||||
expect(finalSpec.members[0].address).toBe('1.2.3.4');
|
||||
expect(finalSpec.members[0].subnet).toBe('subnet-1');
|
||||
expect(finalSpec.members[0].port).toBe(80);
|
||||
expect(finalSpec.members[0].weight).toBe(1);
|
||||
expect(finalSpec.members[1].id).toBe('5678');
|
||||
expect(finalSpec.members[1].address).toBe('5.6.7.8');
|
||||
expect(finalSpec.members[1].subnet).toBe('subnet-1');
|
||||
expect(finalSpec.members[1].port).toBe(80);
|
||||
expect(finalSpec.members[1].weight).toBe(1);
|
||||
|
||||
expect(finalSpec.monitor.type).toBe('HTTP');
|
||||
expect(finalSpec.monitor.interval).toBe(1);
|
||||
expect(finalSpec.monitor.retry).toBe(1);
|
||||
expect(finalSpec.monitor.timeout).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model visible resources (edit listener, no pool)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
delete listenerResources.pool;
|
||||
model.initialize('listener', '1234');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
it('should only show listener details', function() {
|
||||
expect(model.visibleResources).toEqual(['listener']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model visible resources (edit listener, no monitor or existing members)', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
delete listenerResources.members;
|
||||
delete listenerResources.monitor;
|
||||
model.initialize('listener', '1234');
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
it('should only show listener, pool, and member details', function() {
|
||||
expect(model.visibleResources).toEqual(['listener', 'pool', 'members']);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<select class="form-control input-sm" name="monitor-type"
|
||||
id="monitor-type"
|
||||
ng-options="type for type in model.monitorTypes"
|
||||
ng-model="model.spec.monitor.type">
|
||||
ng-model="model.spec.monitor.type"
|
||||
ng-disabled="model.context.id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -105,7 +106,8 @@
|
|||
popover-trigger="hover"></span>
|
||||
<input name="monitor-status" id="monitor-status"
|
||||
type="text" class="form-control input-sm"
|
||||
ng-model="model.spec.monitor.status" ng-pattern="::ctrl.statusPattern">
|
||||
ng-model="model.spec.monitor.status" ng-pattern="::ctrl.statusPattern"
|
||||
ng-disabled="model.context.id">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
id="pool-protocol"
|
||||
ng-options="protocol for protocol in model.poolProtocols"
|
||||
ng-model="model.spec.pool.protocol"
|
||||
ng-change="ctrl.protocolChange(model.spec.pool.protocol)">
|
||||
ng-change="ctrl.protocolChange(model.spec.pool.protocol)"
|
||||
ng-disabled="model.context.id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,7 +48,8 @@
|
|||
<select class="form-control input-sm" name="pool-method"
|
||||
id="pool-method"
|
||||
ng-options="method for method in model.methods"
|
||||
ng-model="model.spec.pool.method">
|
||||
ng-model="model.spec.pool.method"
|
||||
ng-disabled="model.context.id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -67,7 +67,22 @@
|
|||
|
||||
return initWorkflow;
|
||||
|
||||
function initWorkflow(title, icon, steps) {
|
||||
function initWorkflow(title, icon, steps, promise) {
|
||||
|
||||
var filteredSteps = steps ? workflowSteps.filter(function(step) {
|
||||
return steps.indexOf(step.id) > -1;
|
||||
}) : workflowSteps;
|
||||
|
||||
// If a promise is provided then add a checkReadiness function to the first step so
|
||||
// that the workflow will not show until the promise is resolved. There must always
|
||||
// be at least one step in the workflow.
|
||||
if (promise) {
|
||||
filteredSteps[0] = angular.copy(filteredSteps[0]);
|
||||
filteredSteps[0].checkReadiness = function() {
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
|
||||
return dashboardWorkflow({
|
||||
title: title,
|
||||
btnText: {
|
||||
|
@ -76,9 +91,8 @@
|
|||
btnIcon: {
|
||||
finish: icon
|
||||
},
|
||||
steps: steps ? workflowSteps.filter(function(step) {
|
||||
return steps.indexOf(step.id) > -1;
|
||||
}) : workflowSteps
|
||||
steps: filteredSteps,
|
||||
allSteps: workflowSteps
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
var workflow = workflowService('My Workflow', 'foo', ['listener', 'pool']);
|
||||
expect(workflow.steps).toBeDefined();
|
||||
expect(workflow.steps.length).toBe(2);
|
||||
expect(workflow.steps[0].checkReadiness).not.toBeDefined();
|
||||
|
||||
var forms = [
|
||||
'listenerDetailsForm',
|
||||
|
@ -73,6 +74,13 @@
|
|||
});
|
||||
});
|
||||
|
||||
it('can wait for all steps to be ready', function () {
|
||||
var workflow = workflowService('My Workflow', 'foo', null, 'promise');
|
||||
|
||||
expect(workflow.steps[0].checkReadiness).toBeDefined();
|
||||
expect(workflow.steps[0].checkReadiness()).toBe('promise');
|
||||
});
|
||||
|
||||
it('can be extended', function () {
|
||||
var workflow = workflowService('My Workflow');
|
||||
expect(workflow.append).toBeDefined();
|
||||
|
|
Loading…
Reference in New Issue