Merge "Support external members when creating load balancer"
This commit is contained in:
commit
5004fde680
|
@ -46,24 +46,52 @@
|
|||
}
|
||||
}
|
||||
|
||||
transfer-table {
|
||||
.member-weight,
|
||||
.member-port {
|
||||
display: inline-block;
|
||||
width: 6em;
|
||||
/* Load Balancer Wizard */
|
||||
.lbaas-wizard {
|
||||
table {
|
||||
.member-weight,
|
||||
.member-port {
|
||||
width: 6em;
|
||||
}
|
||||
.member-address {
|
||||
width: 20em;
|
||||
}
|
||||
div.form-field {
|
||||
display: inline-block;
|
||||
}
|
||||
span.invalid {
|
||||
vertical-align: top;
|
||||
margin: 8px 0px 0px 5px;
|
||||
}
|
||||
}
|
||||
.member-address {
|
||||
width: 20em;
|
||||
|
||||
.addresses-popover + .popover {
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
span.invalid {
|
||||
vertical-align: top;
|
||||
margin: 8px 0px 0px 5px;
|
||||
|
||||
/* Pool Members tab */
|
||||
[ng-form="memberDetailsForm"] {
|
||||
.transfer-section:first-child {
|
||||
/* Remove the borders around the last row in the top table that has the
|
||||
"Add external member" action in it. */
|
||||
.table-rsp.table-detail tbody tr:nth-last-child(2):not(.expanded) td,
|
||||
.table-rsp.table-detail tbody tr:last-child:not(.spacer-row) td {
|
||||
border-bottom: none;
|
||||
}
|
||||
/* Remove the striped background on the last row in the top table that has the
|
||||
"Add external member" action in it. */
|
||||
.table-rsp.table-detail.table-striped tbody tr:last-child > td {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
.transfer-section:last-child {
|
||||
/* Hide the badge on the bottom table with the instance count. */
|
||||
.transfer-heading .badge {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addresses-popover + .popover {
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
'$scope',
|
||||
'$compile',
|
||||
'horizon.dashboard.project.lbaasv2.popovers',
|
||||
'horizon.dashboard.project.lbaasv2.patterns',
|
||||
'horizon.framework.util.i18n.gettext'
|
||||
];
|
||||
|
||||
|
@ -35,18 +36,21 @@
|
|||
* @param $scope The angular scope object.
|
||||
* @param $compile The angular compile service.
|
||||
* @param popoverTemplates LBaaS v2 popover templates constant.
|
||||
* @param patterns The LBaaS v2 patterns constant.
|
||||
* @param gettext The horizon gettext function for translation.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function MemberDetailsController($scope, $compile, popoverTemplates, gettext) {
|
||||
function MemberDetailsController($scope, $compile, popoverTemplates, patterns, gettext) {
|
||||
var ctrl = this;
|
||||
var memberCounter = 0;
|
||||
|
||||
// Error text for invalid fields
|
||||
ctrl.portError = gettext('The port must be a number between 1 and 65535.');
|
||||
ctrl.weightError = gettext('The weight must be a number between 1 and 256.');
|
||||
ctrl.ipError = gettext('The IP address is not valid.');
|
||||
|
||||
// Table widget properties
|
||||
// Instances transer table widget properties
|
||||
ctrl.tableData = {
|
||||
available: $scope.model.members,
|
||||
allocated: $scope.model.spec.members,
|
||||
|
@ -58,15 +62,27 @@
|
|||
};
|
||||
ctrl.tableHelp = {
|
||||
availHelpText: '',
|
||||
noneAllocText: gettext('Select members from the available members below'),
|
||||
noneAvailText: gettext('No available members')
|
||||
noneAllocText: gettext('No members have been allocated'),
|
||||
noneAvailText: gettext('No available instances'),
|
||||
allocTitle: gettext('Allocated Members'),
|
||||
availTitle: gettext('Available Instances')
|
||||
};
|
||||
|
||||
// IP address validation pattern
|
||||
ctrl.ipPattern = [patterns.ipv4, patterns.ipv6].join('|');
|
||||
|
||||
// Functions to control the IP address popover
|
||||
ctrl.showAddressPopover = showAddressPopover;
|
||||
ctrl.hideAddressPopover = hideAddressPopover;
|
||||
ctrl.addressPopoverTarget = addressPopoverTarget;
|
||||
|
||||
// Member management
|
||||
ctrl.allocateExternalMember = allocateExternalMember;
|
||||
ctrl.allocateMember = allocateMember;
|
||||
ctrl.deallocateMember = deallocateMember;
|
||||
|
||||
ctrl.getSubnetName = getSubnetName;
|
||||
|
||||
//////////
|
||||
|
||||
function showAddressPopover(event, member) {
|
||||
|
@ -91,5 +107,32 @@
|
|||
function addressPopoverTarget(member) {
|
||||
return interpolate(gettext('%(ip)s...'), { ip: member.address.ip }, true);
|
||||
}
|
||||
|
||||
function allocateExternalMember() {
|
||||
var protocol = $scope.model.spec.pool.protocol;
|
||||
$scope.model.spec.members.push({
|
||||
id: memberCounter++,
|
||||
address: null,
|
||||
subnet: null,
|
||||
port: { HTTP: 80, HTTPS: 443 }[protocol],
|
||||
weight: 1
|
||||
});
|
||||
}
|
||||
|
||||
function allocateMember(member) {
|
||||
var newMember = angular.extend(angular.copy(member), { id: memberCounter++ });
|
||||
$scope.model.spec.members.push(newMember);
|
||||
}
|
||||
|
||||
function deallocateMember(member) {
|
||||
var index = $scope.model.spec.members.indexOf(member);
|
||||
$scope.model.spec.members.splice(index, 1);
|
||||
}
|
||||
|
||||
function getSubnetName(member) {
|
||||
return $scope.model.subnets.filter(function filterSubnet(subnet) {
|
||||
return subnet.id === member.address.subnet;
|
||||
})[0].name;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -17,38 +17,51 @@
|
|||
'use strict';
|
||||
|
||||
describe('Member Details Step', function() {
|
||||
var members = [{
|
||||
id: '1',
|
||||
name: 'foo',
|
||||
description: 'bar',
|
||||
weight: 1,
|
||||
port: 80,
|
||||
address: { ip: '1.2.3.4', subnet: '1' },
|
||||
addresses: [{ ip: '1.2.3.4', subnet: '1' },
|
||||
{ ip: '2.3.4.5', subnet: '2' }]
|
||||
}];
|
||||
var model;
|
||||
|
||||
beforeEach(module('horizon.framework.util.i18n'));
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(function() {
|
||||
model = {
|
||||
spec: {
|
||||
members: [],
|
||||
pool: {
|
||||
protocol: 'HTTP'
|
||||
}
|
||||
},
|
||||
members: [{
|
||||
id: '1',
|
||||
name: 'foo',
|
||||
description: 'bar',
|
||||
weight: 1,
|
||||
port: 80,
|
||||
address: { ip: '1.2.3.4', subnet: '1' },
|
||||
addresses: [{ ip: '1.2.3.4', subnet: '1' },
|
||||
{ ip: '2.3.4.5', subnet: '2' }]
|
||||
}],
|
||||
subnets: [{
|
||||
id: '1',
|
||||
name: 'subnet-1'
|
||||
}]
|
||||
};
|
||||
});
|
||||
|
||||
describe('MemberDetailsController', function() {
|
||||
var ctrl, scope;
|
||||
var ctrl;
|
||||
|
||||
beforeEach(inject(function($controller) {
|
||||
scope = {
|
||||
model: {
|
||||
spec: {
|
||||
members: []
|
||||
},
|
||||
members: members
|
||||
}
|
||||
};
|
||||
ctrl = $controller('MemberDetailsController', { $scope: scope });
|
||||
ctrl = $controller('MemberDetailsController', { $scope: { model: model } });
|
||||
}));
|
||||
|
||||
it('should define error messages for invalid fields', function() {
|
||||
expect(ctrl.portError).toBeDefined();
|
||||
expect(ctrl.weightError).toBeDefined();
|
||||
expect(ctrl.ipError).toBeDefined();
|
||||
});
|
||||
|
||||
it('should define patterns for validation', function() {
|
||||
expect(ctrl.ipPattern).toBeDefined();
|
||||
});
|
||||
|
||||
it('should define transfer table properties', function() {
|
||||
|
@ -72,9 +85,36 @@
|
|||
});
|
||||
|
||||
it('should properly format address popover target', function() {
|
||||
var target = ctrl.addressPopoverTarget(members[0]);
|
||||
var target = ctrl.addressPopoverTarget(model.members[0]);
|
||||
expect(target).toBe('1.2.3.4...');
|
||||
});
|
||||
|
||||
it('should allocate a new external member', function() {
|
||||
ctrl.allocateExternalMember();
|
||||
expect(model.spec.members.length).toBe(1);
|
||||
expect(model.spec.members[0].id).toBe(0);
|
||||
expect(model.spec.members[0].address).toBeNull();
|
||||
expect(model.spec.members[0].subnet).toBeNull();
|
||||
});
|
||||
|
||||
it('should allocate a given member', function() {
|
||||
ctrl.allocateMember(model.members[0]);
|
||||
expect(model.spec.members.length).toBe(1);
|
||||
expect(model.spec.members[0].id).toBe(0);
|
||||
expect(model.spec.members[0].address).toEqual(model.members[0].address);
|
||||
expect(model.spec.members[0].subnet).toBeUndefined();
|
||||
expect(model.spec.members[0].port).toEqual(model.members[0].port);
|
||||
});
|
||||
|
||||
it('should deallocate a given member', function() {
|
||||
ctrl.deallocateMember(model.spec.members[0]);
|
||||
expect(model.spec.members.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should show subnet name for available instance', function() {
|
||||
var name = ctrl.getSubnetName(model.members[0]);
|
||||
expect(name).toBe('subnet-1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Member Details Step Template', function() {
|
||||
|
@ -90,21 +130,16 @@
|
|||
var popoverTemplates = $injector.get('horizon.dashboard.project.lbaasv2.popovers');
|
||||
var markup = $templateCache.get(basePath + 'workflow/members/members.html');
|
||||
$scope = $injector.get('$rootScope').$new();
|
||||
$scope.model = {
|
||||
spec: {
|
||||
members: []
|
||||
},
|
||||
members: members
|
||||
};
|
||||
$scope.model = model;
|
||||
$element = $compile(markup)($scope);
|
||||
var popoverScope = $injector.get('$rootScope').$new();
|
||||
popoverScope.member = members[0];
|
||||
popoverScope.member = model.members[0];
|
||||
popoverContent = $compile(popoverTemplates.ipAddresses)(popoverScope);
|
||||
}));
|
||||
|
||||
it('should show IP addresses popover on hover', function() {
|
||||
var ctrl = $element.scope().ctrl;
|
||||
ctrl.tableData.displayedAvailable = members;
|
||||
ctrl.tableData.displayedAvailable = model.members;
|
||||
$scope.$apply();
|
||||
|
||||
var popoverElement = $element.find('span.addresses-popover');
|
||||
|
@ -116,7 +151,7 @@
|
|||
popoverElement.trigger('mouseover');
|
||||
|
||||
expect(ctrl.showAddressPopover).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({type: 'mouseover'}), members[0]);
|
||||
jasmine.objectContaining({type: 'mouseover'}), model.members[0]);
|
||||
expect($.fn.popover.calls.count()).toBe(2);
|
||||
expect($.fn.popover.calls.argsFor(0)[0]).toEqual({
|
||||
content: popoverContent,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<h1 translate>Pool Members Help</h1>
|
||||
|
||||
<p translate>Add members to the load balancer pool. The Available Members table contains existing instances that can be added to the pool.</p>
|
||||
<p translate>The Available Instances table contains existing instances that can be added as members of the pool. Use the "Add external member" button to add a member not found in the Available Instances table.</p>
|
||||
<p translate>Each member must have a unique combination of IP address and port.</p>
|
|
@ -4,7 +4,6 @@
|
|||
<!--content-->
|
||||
<div class="content">
|
||||
<div translate class="subtitle">Add members to the load balancer pool.</div>
|
||||
|
||||
<transfer-table tr-model="ctrl.tableData"
|
||||
limits="::ctrl.tableLimits"
|
||||
help-text="::ctrl.tableHelp">
|
||||
|
@ -16,18 +15,19 @@
|
|||
class="table-striped table-rsp table-detail modern form-group">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="expander"></th>
|
||||
<th class="rsp-p2" translate>Name</th>
|
||||
<th class="rsp-p3" translate>Description</th>
|
||||
<th class="rsp-p1"
|
||||
ng-class="{ 'required': ctrl.tableData.displayedAllocated.length > 0 }">
|
||||
<label translate>IP Address</label>
|
||||
</th>
|
||||
<th class="rsp-p1" translate>Weight</th>
|
||||
<th class="rsp-p1"
|
||||
ng-class="{ 'required': ctrl.tableData.displayedAllocated.length > 0 }">
|
||||
<label translate>Subnet</label>
|
||||
</th>
|
||||
<th class="rsp-p1"
|
||||
ng-class="{ 'required': ctrl.tableData.displayedAllocated.length > 0 }">
|
||||
<label translate>Port</label>
|
||||
</th>
|
||||
<th class="rsp-p1" translate>Weight</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -39,36 +39,40 @@
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-repeat-start="row in ctrl.tableData.displayedAllocated track by row.id">
|
||||
<td class="expander">
|
||||
<i class="fa fa-chevron-right"
|
||||
hz-expand-detail
|
||||
duration="200">
|
||||
</i>
|
||||
</td>
|
||||
<td class="rsp-p2">{$ ::row.name $}</td>
|
||||
<td class="rsp-p3">{$ ::row.description | noValue $}</td>
|
||||
<tr ng-repeat="row in ctrl.tableData.displayedAllocated track by row.id">
|
||||
<td class="rsp-p1">
|
||||
<div ng-if="!row.addresses"
|
||||
class="form-field member-address"
|
||||
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">
|
||||
</div>
|
||||
<span ng-if="!row.addresses"
|
||||
class="fa fa-exclamation-triangle invalid"
|
||||
ng-show="memberDetailsForm['{$ ::row.id $}-address'].$invalid && memberDetailsForm.$dirty"
|
||||
popover="{$ ::ctrl.ipError $}"
|
||||
popover-placement="top" popover-append-to-body="true"
|
||||
popover-trigger="hover"></span>
|
||||
<span ng-if="row.addresses.length === 1">{$ row.address.ip $}</span>
|
||||
<div ng-if="row.addresses.length > 1"
|
||||
class="form-field member-address">
|
||||
<select class="form-control input-sm"
|
||||
ng-options="addr.ip for addr in row.addresses"
|
||||
ng-model="row.address" ng-required="true">
|
||||
ng-model="row.address" ng-required="true"
|
||||
ng-if="row.addresses">
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td class="rsp-p1">
|
||||
<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">
|
||||
<div ng-if="!row.addresses"
|
||||
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">
|
||||
</select>
|
||||
</div>
|
||||
<span class="fa fa-exclamation-triangle invalid"
|
||||
ng-show="memberDetailsForm['{$ ::row.id $}-weight'].$invalid && memberDetailsForm.$dirty"
|
||||
popover="{$ ::ctrl.weightError $}"
|
||||
popover-placement="top" popover-append-to-body="true"
|
||||
popover-trigger="hover"></span>
|
||||
<span ng-if="row.addresses">{$ ctrl.getSubnetName(row) $}</span>
|
||||
</td>
|
||||
<td class="rsp-p1">
|
||||
<div class="form-field member-port"
|
||||
|
@ -83,27 +87,35 @@
|
|||
popover-placement="top" popover-append-to-body="true"
|
||||
popover-trigger="hover"></span>
|
||||
</td>
|
||||
<td class="rsp-p1">
|
||||
<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">
|
||||
</div>
|
||||
<span class="fa fa-exclamation-triangle invalid"
|
||||
ng-show="memberDetailsForm['{$ ::row.id $}-weight'].$invalid && memberDetailsForm.$dirty"
|
||||
popover="{$ ::ctrl.weightError $}"
|
||||
popover-placement="top" popover-append-to-body="true"
|
||||
popover-trigger="hover"></span>
|
||||
</td>
|
||||
<td class="action-col">
|
||||
<action-list>
|
||||
<action action-classes="'btn btn-sm btn-default'"
|
||||
callback="trCtrl.deallocate" item="row">
|
||||
<span class="fa fa-minus"></span>
|
||||
callback="ctrl.deallocateMember" item="row">
|
||||
<span translate>Remove</span>
|
||||
</action>
|
||||
</action-list>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-repeat-end class="detail-row">
|
||||
<td class="detail" colspan="100">
|
||||
<div class="row">
|
||||
<dl class="rsp-alt-p2 col-sm-2">
|
||||
<dt translate>Name</dt>
|
||||
<dd>{$ ::row.name $}</dd>
|
||||
</dl>
|
||||
<dl class="rsp-alt-p3 col-sm-2">
|
||||
<dt translate>Description</dt>
|
||||
<dd>{$ ::row.description | noValue $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<tr>
|
||||
<td colspan="100">
|
||||
<action-list class="pull-right">
|
||||
<action action-classes="'btn btn-sm btn-default'"
|
||||
callback="ctrl.allocateExternalMember">
|
||||
<span translate>Add external member</span>
|
||||
</action>
|
||||
</action-list>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -131,7 +143,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-if="trCtrl.numAvailable() === 0">
|
||||
<tr ng-if="ctrl.tableData.available.length === 0">
|
||||
<td colspan="100">
|
||||
<div class="no-rows-help">
|
||||
{$ ::trCtrl.helpText.noneAvailText $}
|
||||
|
@ -161,8 +173,8 @@
|
|||
<td class="action-col">
|
||||
<action-list>
|
||||
<action action-classes="'btn btn-sm btn-default'"
|
||||
callback="trCtrl.allocate" item="row">
|
||||
<span class="fa fa-plus"></span>
|
||||
callback="ctrl.allocateMember" item="row">
|
||||
<span translate>Add</span>
|
||||
</action>
|
||||
</action-list>
|
||||
</td>
|
||||
|
@ -184,8 +196,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</available>
|
||||
|
||||
</transfer-table> <!-- End Transfer Table -->
|
||||
|
||||
</div> <!-- end content -->
|
||||
</div>
|
||||
|
|
|
@ -83,7 +83,8 @@
|
|||
var spec = {
|
||||
backdrop: 'static',
|
||||
controller: 'ModalContainerController',
|
||||
template: '<wizard ng-controller="' + args.controller + '"></wizard>',
|
||||
template: '<wizard class="lbaas-wizard" ng-controller="' +
|
||||
args.controller + '"></wizard>',
|
||||
windowClass: 'modal-dialog-wizard',
|
||||
resolve: {
|
||||
launchContext: function() {
|
||||
|
|
|
@ -253,16 +253,33 @@
|
|||
// subnet, and port so we can assume those exist here.
|
||||
if (!finalSpec.pool || finalSpec.members.length === 0) {
|
||||
delete finalSpec.members;
|
||||
return;
|
||||
}
|
||||
|
||||
var members = [];
|
||||
angular.forEach(finalSpec.members, function cleanMember(member) {
|
||||
delete member.id;
|
||||
delete member.addresses;
|
||||
delete member.name;
|
||||
delete member.description;
|
||||
member.subnet = member.address.subnet;
|
||||
member.address = member.address.ip;
|
||||
if (member.address && member.port) {
|
||||
['id', 'name', 'description', 'addresses'].forEach(function deleteProperty(prop) {
|
||||
if (angular.isDefined(member[prop])) {
|
||||
delete member[prop];
|
||||
}
|
||||
});
|
||||
if (angular.isObject(member.address)) {
|
||||
member.subnet = member.address.subnet;
|
||||
member.address = member.address.ip;
|
||||
} else if (member.subnet) {
|
||||
member.subnet = member.subnet.id;
|
||||
} else {
|
||||
delete member.subnet;
|
||||
}
|
||||
members.push(member);
|
||||
}
|
||||
});
|
||||
if (members.length > 0) {
|
||||
finalSpec.members = members;
|
||||
} else {
|
||||
delete finalSpec.members;
|
||||
}
|
||||
}
|
||||
|
||||
function cleanFinalSpecMonitor(finalSpec) {
|
||||
|
|
|
@ -379,6 +379,24 @@
|
|||
description: 'bar',
|
||||
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;
|
||||
|
@ -399,7 +417,7 @@
|
|||
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(1);
|
||||
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);
|
||||
|
@ -407,7 +425,16 @@
|
|||
expect(finalSpec.members[0].addresses).toBeUndefined();
|
||||
expect(finalSpec.members[0].id).toBeUndefined();
|
||||
expect(finalSpec.members[0].name).toBeUndefined();
|
||||
expect(finalSpec.members[0].description).toBeUndefined();
|
||||
expect(finalSpec.members[1].id).toBeUndefined();
|
||||
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[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.monitor.type).toBe('PING');
|
||||
expect(finalSpec.monitor.interval).toBe(1);
|
||||
expect(finalSpec.monitor.retry).toBe(1);
|
||||
|
@ -463,6 +490,27 @@
|
|||
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 = 'HTTPS';
|
||||
model.spec.listener.port = 80;
|
||||
model.spec.pool.protocol = 'HTTP';
|
||||
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];
|
||||
|
|
|
@ -43,13 +43,11 @@
|
|||
//////////
|
||||
|
||||
function protocolChange(protocol) {
|
||||
var port = '';
|
||||
if (protocol === 'HTTP') {
|
||||
port = 80;
|
||||
} else if (protocol === 'HTTPS') {
|
||||
port = 443;
|
||||
}
|
||||
$scope.model.members.forEach(function setPort(member) {
|
||||
var port = { HTTP: 80, HTTPS: 443 }[protocol];
|
||||
$scope.model.members.forEach(function setAvailableInstancePort(member) {
|
||||
member.port = port;
|
||||
});
|
||||
$scope.model.spec.members.forEach(function setAllocatedMemberPort(member) {
|
||||
member.port = port;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,14 +18,18 @@
|
|||
|
||||
describe('Create Pool Details Step', function() {
|
||||
var ctrl;
|
||||
var members = [{port: ''}, {port: ''}];
|
||||
var availableMembers = [{port: ''}, {port: ''}];
|
||||
var allocatedMembers = [{port: ''}, {port: ''}];
|
||||
|
||||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(inject(function($controller) {
|
||||
var scope = {
|
||||
model: {
|
||||
members: members
|
||||
members: availableMembers,
|
||||
spec: {
|
||||
members: allocatedMembers
|
||||
}
|
||||
}
|
||||
};
|
||||
ctrl = $controller('CreatePoolDetailsController', { $scope: scope });
|
||||
|
@ -38,7 +42,7 @@
|
|||
it('should update member ports on protocol change to HTTP', function() {
|
||||
ctrl.protocolChange('HTTP');
|
||||
|
||||
members.forEach(function(member) {
|
||||
availableMembers.concat(allocatedMembers).forEach(function(member) {
|
||||
expect(member.port).toBe(80);
|
||||
});
|
||||
});
|
||||
|
@ -46,7 +50,7 @@
|
|||
it('should update member ports on protocol change to HTTPS', function() {
|
||||
ctrl.protocolChange('HTTPS');
|
||||
|
||||
members.forEach(function(member) {
|
||||
availableMembers.concat(allocatedMembers).forEach(function(member) {
|
||||
expect(member.port).toBe(443);
|
||||
});
|
||||
});
|
||||
|
@ -54,8 +58,8 @@
|
|||
it('should update member ports on protocol change to TCP', function() {
|
||||
ctrl.protocolChange('TCP');
|
||||
|
||||
members.forEach(function(member) {
|
||||
expect(member.port).toBe('');
|
||||
availableMembers.concat(allocatedMembers).forEach(function(member) {
|
||||
expect(member.port).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue