mirror of https://github.com/rancher/ui.git
Advanced LB service toggle, new port format
This commit is contained in:
parent
3f4fbeff82
commit
fb9cef34aa
|
|
@ -0,0 +1,15 @@
|
||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
tgt: null,
|
||||||
|
targetChoices: null,
|
||||||
|
isAdvanced: null,
|
||||||
|
|
||||||
|
tagName: 'TR',
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
remove: function() {
|
||||||
|
this.sendAction('remove', this.get('tgt'));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<td>
|
||||||
|
{{input classNames="form-control input-sm" value=tgt.hostname placeholder="e.g. svc.com"}}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="form-control-static input-sm">:</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{input classNames="form-control input-sm" value=tgt.srcPort placeholder="e.g. 80"}}
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
<td>
|
||||||
|
{{input classNames="form-control input-sm" value=tgt.path placeholder="e.g. /svc"}}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="form-control-static input-sm"><i class="ss-right"></i></div>
|
||||||
|
</td>
|
||||||
|
{{/if}}
|
||||||
|
<td>
|
||||||
|
{{display-name-select
|
||||||
|
classNames="form-control input-sm lb-target"
|
||||||
|
prompt="Select a service..."
|
||||||
|
value=tgt.value
|
||||||
|
content=targetChoices
|
||||||
|
optionValuePath="content.id"
|
||||||
|
optionLabelPath="content.name"
|
||||||
|
optionGroupPath="group"
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<td> </td>
|
||||||
|
<td>
|
||||||
|
{{input classNames="form-control input-sm" value=tgt.dstPort placeholder="e.g. 8080"}}
|
||||||
|
</td>
|
||||||
|
{{/if}}
|
||||||
|
<td class="text-right">
|
||||||
|
<button {{action "remove"}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
||||||
|
</td>
|
||||||
|
|
@ -201,7 +201,7 @@ export default Ember.Component.extend({
|
||||||
out.pushObjects(keys);
|
out.pushObjects(keys);
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('allHosts.@each.labels'),
|
}.property('allHosts.@each.labels'),
|
||||||
|
|
||||||
hostLabelValueChoices: function() {
|
hostLabelValueChoices: function() {
|
||||||
|
|
@ -217,7 +217,7 @@ export default Ember.Component.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('userKey','allHosts.@each.labels'),
|
}.property('userKey','allHosts.@each.labels'),
|
||||||
|
|
||||||
allContainers: function() {
|
allContainers: function() {
|
||||||
|
|
@ -243,7 +243,7 @@ export default Ember.Component.extend({
|
||||||
out.pushObjects(keys);
|
out.pushObjects(keys);
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('allContainers.@each.labels'),
|
}.property('allContainers.@each.labels'),
|
||||||
|
|
||||||
containerLabelValueChoices: function() {
|
containerLabelValueChoices: function() {
|
||||||
|
|
@ -258,7 +258,7 @@ export default Ember.Component.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('userKey','allContainers.@each.labels'),
|
}.property('userKey','allContainers.@each.labels'),
|
||||||
|
|
||||||
containerValueChoices: function() {
|
containerValueChoices: function() {
|
||||||
|
|
@ -271,7 +271,7 @@ export default Ember.Component.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('allContainers.@each.name'),
|
}.property('allContainers.@each.name'),
|
||||||
|
|
||||||
serviceValueChoices: function() {
|
serviceValueChoices: function() {
|
||||||
|
|
@ -285,6 +285,6 @@ export default Ember.Component.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return out.sort().uniq();
|
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||||
}.property('allContainers.@each.labels'),
|
}.property('allContainers.@each.labels'),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
<span class="sr-only">Toggle Dropdown</span>
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
<li>{{#link-to "service.new-alias" (query-params environmentId=model.id)}}Add Service Alias{{/link-to}}</li>
|
|
||||||
<li>{{#link-to "service.new-balancer" (query-params environmentId=model.id)}}Add Load Balancer{{/link-to}}</li>
|
<li>{{#link-to "service.new-balancer" (query-params environmentId=model.id)}}Add Load Balancer{{/link-to}}</li>
|
||||||
|
<li>{{#link-to "service.new-alias" (query-params environmentId=model.id)}}Add Service Alias{{/link-to}}</li>
|
||||||
<li>{{#link-to "service.new-external" (query-params environmentId=model.id)}}Add External Service{{/link-to}}</li>
|
<li>{{#link-to "service.new-external" (query-params environmentId=model.id)}}Add External Service{{/link-to}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,105 +1,48 @@
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
|
|
||||||
// New Format: [hostname][:srcPort][/path]:dstPort
|
// New Format: [hostname][:srcPort][/path][=dstPort]
|
||||||
// Older format: dstPort:[hostname][/path]
|
// Older format: dstPort:[hostname][/path]
|
||||||
export function parseTarget(str) {
|
export function parseTarget(str) {
|
||||||
var srcPort = null, dstPort = null, hostname = null, path = null;
|
var srcPort = null, dstPort = null, hostname = null, path = null;
|
||||||
var idx;
|
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
|
|
||||||
var parts = str.split(':');
|
var match;
|
||||||
if ( parts.length === 2 )
|
if ( match = str.match(/^(\d+)$/) )
|
||||||
{
|
{
|
||||||
if ( !parts[0].length || !parts[1].length)
|
// New Format: just a dstPort
|
||||||
{
|
hostname = null;
|
||||||
// Invalid: ":something" or "something:"
|
srcPort = null;
|
||||||
return null;
|
path = null;
|
||||||
}
|
dstPort = parseInt(match[1], 10);
|
||||||
|
|
||||||
if ( parts[0].match(/^[0-9]+$/) )
|
|
||||||
{
|
|
||||||
// old: dstPort:[hostname][/path] or new: /path:dstPort
|
|
||||||
if ( parts[1].match(/^[0-9]+$/) )
|
|
||||||
{
|
|
||||||
srcPort = parseInt(parts[0], 10);
|
|
||||||
dstPort = parseInt(parts[1], 10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstPort = parseInt(parts[0], 10);
|
|
||||||
|
|
||||||
idx = parts[1].indexOf('/');
|
|
||||||
if ( idx >= 0 )
|
|
||||||
{
|
|
||||||
hostname = parts[1].substr(0,idx) || null;
|
|
||||||
path = parts[1].substr(idx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hostname = parts[1];
|
|
||||||
path = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// new: [hostname][/path]:dstPort or srcPort[/path]:dstPort
|
|
||||||
dstPort = parseInt(parts[1], 10);
|
|
||||||
idx = parts[0].indexOf('/');
|
|
||||||
if ( idx === -1 )
|
|
||||||
{
|
|
||||||
srcPort = null;
|
|
||||||
hostname = parts[0];
|
|
||||||
path = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var begin = parts[0].substr(0,idx);
|
|
||||||
var end = parts[0].substr(idx);
|
|
||||||
|
|
||||||
if ( begin.match(/^[0-9]+$/) )
|
|
||||||
{
|
|
||||||
// new: srcPort[/path]:dstPort
|
|
||||||
hostname = null;
|
|
||||||
srcPort = parseInt(begin, 10);
|
|
||||||
path = end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// new: hostname/path:dstPort
|
|
||||||
hostname = begin || null;
|
|
||||||
srcPort = null;
|
|
||||||
path = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ( parts.length === 3)
|
else if ( match = str.match(/(\d+):([^\/]+)?(\/.*)?$/) )
|
||||||
{
|
{
|
||||||
if ( !parts[0].length || !parts[1].length || !parts[2].length)
|
// Old Format: dstPort[:hostname][/path]
|
||||||
|
hostname = match[2] || null;
|
||||||
|
srcPort = null;
|
||||||
|
path = match[3] || null;
|
||||||
|
dstPort = parseInt(match[1], 10);
|
||||||
|
}
|
||||||
|
else if ( match = str.match(/([^/=:]+)?(:(\d+))?(\/[^=]+)?(=(\d+))?$/) )
|
||||||
|
{
|
||||||
|
// New Format: [hostname][:srcPort][/path][=dstPort]
|
||||||
|
if ( match[1] && match[1].match(/^\d+$/) )
|
||||||
{
|
{
|
||||||
// Invalid: ":something" or "something:" or "something::something"
|
// It's a port
|
||||||
return null;
|
hostname = null;
|
||||||
}
|
srcPort = parseInt(match[1], 10) || null;
|
||||||
|
|
||||||
// [hostname]:srcPort[/path]:dstPort
|
|
||||||
dstPort = parseInt(parts[2], 10);
|
|
||||||
hostname = parts[0];
|
|
||||||
idx = parts[1].indexOf('/');
|
|
||||||
if ( idx === -1 )
|
|
||||||
{
|
|
||||||
srcPort = parseInt(parts[1], 10);
|
|
||||||
path = null;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
srcPort = parseInt(parts[1].substr(0,idx), 10);
|
hostname = match[1] || null;
|
||||||
path = parts[1].substr(idx);
|
srcPort = parseInt(match[3], 10) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dstPort = parseInt(match[6], 10) || null;
|
||||||
|
path = match[4] || null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Invalid
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,18 +60,24 @@ export function stringifyTarget(tgt) {
|
||||||
var hostname = Ember.get(tgt,'hostname');
|
var hostname = Ember.get(tgt,'hostname');
|
||||||
var path = Ember.get(tgt,'path');
|
var path = Ember.get(tgt,'path');
|
||||||
|
|
||||||
// New Format: [hostname][:srcPort][/path]:dstPort
|
// New Format: [hostname][:srcPort][/path][=dstPort]
|
||||||
if ( hostname || srcPort || path )
|
if ( hostname || path || dstPort )
|
||||||
{
|
{
|
||||||
var str = hostname || '';
|
var str = hostname || '';
|
||||||
if ( srcPort )
|
if ( srcPort )
|
||||||
{
|
{
|
||||||
str += (str ? ':' : '') + srcPort;
|
str += (str ? ':' : '') + srcPort;
|
||||||
}
|
}
|
||||||
if ( path ) {
|
|
||||||
str += path;
|
if ( path )
|
||||||
|
{
|
||||||
|
str += (path.substr(0,1) === '/' ? '' : '/') + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dstPort )
|
||||||
|
{
|
||||||
|
str += (str ? '=' : '') + dstPort;
|
||||||
}
|
}
|
||||||
str += ':' + dstPort;
|
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
@ -140,8 +89,25 @@ export function stringifyTarget(tgt) {
|
||||||
|
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
export default Ember.Mixin.create({
|
||||||
|
actions: {
|
||||||
|
addTargetService: function() {
|
||||||
|
this.get('targetsArray').pushObject(Ember.Object.create({isService: true, isAdvanced: false, value: null}));
|
||||||
|
},
|
||||||
|
removeTarget: function(obj) {
|
||||||
|
this.get('targetsArray').removeObject(obj);
|
||||||
|
},
|
||||||
|
|
||||||
|
setAdvanced: function() {
|
||||||
|
this.set('isAdvanced', true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
isAdvanced: false,
|
||||||
|
|
||||||
targetsArray: null,
|
targetsArray: null,
|
||||||
initTargets: function(service) {
|
initTargets: function(service) {
|
||||||
|
this.set('isAdvanced', false);
|
||||||
|
|
||||||
var out = [];
|
var out = [];
|
||||||
var existing = null;
|
var existing = null;
|
||||||
if ( service )
|
if ( service )
|
||||||
|
|
@ -156,8 +122,14 @@ export default Ember.Mixin.create({
|
||||||
var obj = parseTarget(str);
|
var obj = parseTarget(str);
|
||||||
if ( obj )
|
if ( obj )
|
||||||
{
|
{
|
||||||
|
if ( obj.get('hostname') || obj.get('srcPort') || obj.get('path') || obj.get('dstPort') )
|
||||||
|
{
|
||||||
|
this.set('isAdvanced', true);
|
||||||
|
}
|
||||||
|
|
||||||
obj.setProperties({
|
obj.setProperties({
|
||||||
isService: true,
|
isService: true,
|
||||||
|
isAdvanced: false,
|
||||||
value: map.get('service.id'),
|
value: map.get('service.id'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -166,13 +138,17 @@ export default Ember.Mixin.create({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.pushObject(Ember.Object.create({isService: true, isAdvanced: false, value: null}));
|
||||||
|
}
|
||||||
|
|
||||||
this.set('targetsArray', out);
|
this.set('targetsArray', out);
|
||||||
},
|
},
|
||||||
|
|
||||||
targetResources: function() {
|
targetResources: function() {
|
||||||
var out = [];
|
var out = [];
|
||||||
this.get('targetsArray').filterProperty('isService',true).filterProperty('value').filterProperty('dstPort').map((choice) => {
|
this.get('targetsArray').filterProperty('isService',true).filterProperty('value').map((choice) => {
|
||||||
var serviceId = Ember.get(choice,'value');
|
var serviceId = Ember.get(choice,'value');
|
||||||
|
|
||||||
var entry = out.filterProperty('serviceId', serviceId)[0];
|
var entry = out.filterProperty('serviceId', serviceId)[0];
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ import NewOrEdit from 'ui/mixins/new-or-edit';
|
||||||
import ShellQuote from 'npm:shell-quote';
|
import ShellQuote from 'npm:shell-quote';
|
||||||
import Util from 'ui/utils/util';
|
import Util from 'ui/utils/util';
|
||||||
import EditHealthCheck from 'ui/mixins/edit-healthcheck';
|
import EditHealthCheck from 'ui/mixins/edit-healthcheck';
|
||||||
import EditLabels from 'ui/mixins/edit-labels';
|
import EditScheduling from 'ui/mixins/edit-scheduling';
|
||||||
|
|
||||||
export default Ember.Mixin.create(NewOrEdit, EditHealthCheck, EditLabels, {
|
export default Ember.Mixin.create(NewOrEdit, EditHealthCheck, EditScheduling, {
|
||||||
needs: ['hosts'],
|
needs: ['hosts'],
|
||||||
queryParams: ['tab','hostId','advanced'],
|
queryParams: ['tab','hostId','advanced'],
|
||||||
tab: 'command',
|
tab: 'command',
|
||||||
|
|
@ -132,14 +132,6 @@ export default Ember.Mixin.create(NewOrEdit, EditHealthCheck, EditLabels, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addSchedulingRule: function() {
|
|
||||||
this.send('addSystemLabel','','','affinity');
|
|
||||||
},
|
|
||||||
|
|
||||||
removeSchedulingRule: function(obj) {
|
|
||||||
this.send('removeLabel', obj);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ export default Ember.Mixin.create(EditHealthCheck,{
|
||||||
name: 'uilistener',
|
name: 'uilistener',
|
||||||
isPublic: true,
|
isPublic: true,
|
||||||
sourcePort: '',
|
sourcePort: '',
|
||||||
sourceProtocol: 'tcp',
|
sourceProtocol: 'http',
|
||||||
targetPort: '',
|
targetPort: '',
|
||||||
targetProtocol: 'tcp',
|
targetProtocol: 'http',
|
||||||
algorithm: 'roundrobin',
|
algorithm: 'roundrobin',
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import Ember from 'ember';
|
||||||
|
import EditLabels from 'ui/mixins/edit-labels';
|
||||||
|
|
||||||
|
export default Ember.Mixin.create(EditLabels, {
|
||||||
|
actions: {
|
||||||
|
addSchedulingRule: function() {
|
||||||
|
this.send('addSystemLabel','','','affinity');
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSchedulingRule: function(obj) {
|
||||||
|
this.send('removeLabel', obj);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -2,8 +2,9 @@ import Ember from 'ember';
|
||||||
import Cattle from 'ui/utils/cattle';
|
import Cattle from 'ui/utils/cattle';
|
||||||
import EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
import EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
||||||
import EditBalancerTarget from 'ui/mixins/edit-balancer-target';
|
import EditBalancerTarget from 'ui/mixins/edit-balancer-target';
|
||||||
|
import EditScheduling from 'ui/mixins/edit-scheduling';
|
||||||
|
|
||||||
export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLoadBalancerConfig, EditBalancerTarget, {
|
export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLoadBalancerConfig, EditBalancerTarget, EditScheduling, {
|
||||||
queryParams: ['environmentId','serviceId','tab'],
|
queryParams: ['environmentId','serviceId','tab'],
|
||||||
environmentId: null,
|
environmentId: null,
|
||||||
serviceId: null,
|
serviceId: null,
|
||||||
|
|
@ -11,15 +12,8 @@ export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLo
|
||||||
error: null,
|
error: null,
|
||||||
editing: false,
|
editing: false,
|
||||||
primaryResource: Ember.computed.alias('model.balancer'),
|
primaryResource: Ember.computed.alias('model.balancer'),
|
||||||
|
labelResource: Ember.computed.alias('model.launchConfig'),
|
||||||
actions: {
|
isGlobal: false,
|
||||||
addTargetService: function() {
|
|
||||||
this.get('targetsArray').pushObject({isService: true, value: null, protocol: 'http'});
|
|
||||||
},
|
|
||||||
removeTarget: function(obj) {
|
|
||||||
this.get('targetsArray').removeObject(obj);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
initFields: function() {
|
initFields: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
@ -56,19 +50,19 @@ export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLo
|
||||||
}
|
}
|
||||||
|
|
||||||
var bad = this.get('targetsArray').filter(function(obj) {
|
var bad = this.get('targetsArray').filter(function(obj) {
|
||||||
return !Ember.get(obj,'value') || !Ember.get(obj, 'dstPort');
|
return !Ember.get(obj,'value');
|
||||||
});
|
});
|
||||||
if ( bad.get('length') )
|
if ( bad.get('length') )
|
||||||
{
|
{
|
||||||
errors.push('Target Service and Port are required on each Target');
|
errors.push('Target Service is required on each Target');
|
||||||
}
|
}
|
||||||
|
|
||||||
bad = this.get('targetsArray').filter(function(obj) {
|
bad = this.get('targetsArray').filter(function(obj) {
|
||||||
return !Ember.get(obj,'hostname') && !Ember.get(obj, 'srcPort') && !Ember.get(obj,'path');
|
return Ember.get('srcPort') && !Ember.get(obj,'hostname') && !Ember.get(obj, 'dstPort') && !Ember.get(obj,'path');
|
||||||
});
|
});
|
||||||
if ( bad.get('length') )
|
if ( bad.get('length') )
|
||||||
{
|
{
|
||||||
errors.push('At least one of Request Host, Port, or Path are required on each Target');
|
errors.push('A Target can\'t have just a Source Port. Add Request Host, Request Path, or Target Port, or remove the Source Port.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( errors.length )
|
if ( errors.length )
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ export default Ember.Route.extend({
|
||||||
resetController: function (controller, isExisting/*, transition*/) {
|
resetController: function (controller, isExisting/*, transition*/) {
|
||||||
if (isExisting)
|
if (isExisting)
|
||||||
{
|
{
|
||||||
controller.set('tab', 'listeners');
|
controller.set('tab', 'stickiness');
|
||||||
controller.set('stickiness', 'none');
|
controller.set('stickiness', 'none');
|
||||||
controller.set('environmentId', null);
|
controller.set('environmentId', null);
|
||||||
controller.set('serviceId', null);
|
controller.set('serviceId', null);
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,22 @@
|
||||||
{{partial "loadbalancer/edit-targets"}}
|
{{partial "loadbalancer/edit-targets"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||||
|
<p class="help-block">If Request Host and/or Path are specified, connections to HTTP listening ports will be routed to the appropriate target based on the request. For example, you could use this to send traffic for domain1.com to one service and domain2.com to a different service.</p>
|
||||||
|
<p class="help-block">Matching requests will be sent to the Target Service on the Target Port. If that is not set, then the Default Target port for the Source Port. If that is also not set, then the Source Port.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{#if targetsArray.length}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||||
|
<button {{action "setAdvanced"}} class="btn btn-link btn-sm" type="button">Show advanced routing options</button><small>– Direct requests to different services based on port HTTP Host header, or request path</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{{partial "form-divider"}}
|
{{partial "form-divider"}}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ import SelectTab from 'ui/mixins/select-tab';
|
||||||
|
|
||||||
export default Ember.View.extend(SelectTab, {
|
export default Ember.View.extend(SelectTab, {
|
||||||
actions: {
|
actions: {
|
||||||
addTargetService: addAction('addTargetService', '.lb-target'),
|
addTargetService: addAction('addTargetService', '.lb-target'),
|
||||||
addListener: addAction('addListener', '.lb-listener-source-port'),
|
addListener: addAction('addListener', '.lb-listener-source-port'),
|
||||||
|
addSchedulingRule: addAction('addSchedulingRule','.schedule-rule'),
|
||||||
|
addLabel: addAction('addLabel', '.label-key'),
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
|
|
|
||||||
|
|
@ -30,32 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#unless isRequestedHost}}
|
{{#unless isRequestedHost}}
|
||||||
<div class="form-control-static">
|
{{partial "container/scheduling-rules"}}
|
||||||
<button class="btn-circle-plus" {{action "addSchedulingRule" target="view"}}></button>
|
|
||||||
</div>
|
|
||||||
{{#if affinityLabelArray.length}}
|
|
||||||
<table class="table fixed no-lines no-top-padding tight small">
|
|
||||||
<thead>
|
|
||||||
<tr class="text-muted">
|
|
||||||
<th width="70"></th>
|
|
||||||
<th width="100">Condition</th>
|
|
||||||
<th width="60"></th>
|
|
||||||
<th width="180">Field</th>
|
|
||||||
<th width="30"></th>
|
|
||||||
<th>Key</th>
|
|
||||||
<th width="30"></th>
|
|
||||||
<th>Value</th>
|
|
||||||
<th width="30"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{#each labelArray as |rule|}}
|
|
||||||
{{#if (eq rule.type "affinity")}}
|
|
||||||
{{scheduling-rule-row rule=rule allHosts=allHosts remove="removeSchedulingRule" isGlobal=isGlobal}}
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{{/if}}
|
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<div class="form-control-static">
|
||||||
|
<button class="btn-circle-plus btn-circle-text" {{action "addSchedulingRule" target="view"}}> Add Scheduling Rule</button>
|
||||||
|
</div>
|
||||||
|
{{#if affinityLabelArray.length}}
|
||||||
|
<table class="table fixed no-lines no-top-padding tight small">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-muted">
|
||||||
|
<th width="70"></th>
|
||||||
|
<th width="100">Condition</th>
|
||||||
|
<th width="60"></th>
|
||||||
|
<th width="180">Field</th>
|
||||||
|
<th width="30"></th>
|
||||||
|
<th>Key</th>
|
||||||
|
<th width="30"></th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th width="30"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each labelArray as |rule|}}
|
||||||
|
{{#if (eq rule.type "affinity")}}
|
||||||
|
{{scheduling-rule-row rule=rule allHosts=allHosts remove="removeSchedulingRule" isGlobal=isGlobal}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{/if}}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="form-control-static">
|
<div class="form-control-static">
|
||||||
<button class="btn-circle-plus" {{action "addLabel" target="view"}}></button>
|
<button class="btn-circle-plus btn-circle-text" {{action "addLabel" target="view"}}> Add Label</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if userLabelArray.length}}
|
{{#if userLabelArray.length}}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<section class="text-center" style="padding: 0;">
|
<section class="text-center" style="padding: 0;">
|
||||||
<ul class="nav nav-pills" style="display: inline-block">
|
<ul class="nav nav-pills" style="display: inline-block">
|
||||||
<li role="presentation" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=view}}><a>Stickiness</a></li>
|
<li role="presentation" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=view}}><a>Stickiness</a></li>
|
||||||
|
<li role="presentation" class="tab" data-section="labels" {{action "selectTab" "labels" target=view}}><a>Labels</a></li>
|
||||||
|
<li role="presentation" class="tab" data-section="scheduling" {{action "selectTab" "scheduling" target=view}}><a>Scheduling</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -8,5 +10,21 @@
|
||||||
<div class="section container-fluid tab-section" data-section="stickiness">
|
<div class="section container-fluid tab-section" data-section="stickiness">
|
||||||
{{partial "loadbalancer/edit-stickiness"}}
|
{{partial "loadbalancer/edit-stickiness"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section" data-section="labels">
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-sm-12 col-md-2 form-label">
|
||||||
|
<label class="form-control-static">Labels</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-8">
|
||||||
|
{{partial "edit-labels"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section" data-section="scheduling">
|
||||||
|
<p>Automatically pick hosts for each balancer container matching scheduling rules:</p>
|
||||||
|
{{partial "container/scheduling-rules"}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,47 +2,26 @@
|
||||||
<table class="grid fixed no-lines no-top-padding tight" style="margin-bottom: 0;">
|
<table class="grid fixed no-lines no-top-padding tight" style="margin-bottom: 0;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Request Host</th>
|
{{#if isAdvanced}}
|
||||||
<th width="10"> </th>
|
<th>Request Host</th>
|
||||||
<th>Source Port</th>
|
<th width="10"> </th>
|
||||||
<th width="10"> </th>
|
<th>Source Port</th>
|
||||||
<th>Request Path</th>
|
<th width="10"> </th>
|
||||||
<th width="30"> </th>
|
<th>Request Path</th>
|
||||||
|
<th width="30"> </th>
|
||||||
|
{{/if}}
|
||||||
<th>Target Service*</th>
|
<th>Target Service*</th>
|
||||||
<th width="10"> </th>
|
{{#if isAdvanced}}
|
||||||
<th width="90">Target Port*</th>
|
<th width="10"> </th>
|
||||||
|
<th width="90">Target Port</th>
|
||||||
|
{{/if}}
|
||||||
<th width="30"> </th>
|
<th width="30"> </th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each targetsArray as |tgt|}}
|
{{#each targetsArray as |tgt|}}
|
||||||
<tr>
|
{{loadbalancer-target-row tgt=tgt targetChoices=targetChoices remove="removeTarget" isAdvanced=isAdvanced}}
|
||||||
<td>{{input classNames="form-control input-sm" value=tgt.hostname placeholder="e.g. svc.com"}}</td>
|
|
||||||
<td class="text-center"><div class="form-control-static input-sm">:</div></td>
|
|
||||||
<td>{{input classNames="form-control input-sm" value=tgt.srcPort placeholder="e.g. 80"}}</td>
|
|
||||||
<td> </td>
|
|
||||||
<td>{{input classNames="form-control input-sm" value=tgt.path placeholder="e.g. /svc"}}</td>
|
|
||||||
<td class="text-center"><div class="form-control-static input-sm"><i class="ss-right"></i></div></td>
|
|
||||||
<td>
|
|
||||||
{{display-name-select
|
|
||||||
classNames="form-control input-sm lb-target"
|
|
||||||
prompt="Select a service..."
|
|
||||||
value=tgt.value
|
|
||||||
content=targetChoices
|
|
||||||
optionValuePath="content.id"
|
|
||||||
optionLabelPath="content.name"
|
|
||||||
optionGroupPath="group"
|
|
||||||
}}
|
|
||||||
</td>
|
|
||||||
<td> </td>
|
|
||||||
<td>{{input classNames="form-control input-sm" value=tgt.dstPort placeholder="e.g. 8080"}}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<button {{action "removeTarget" tgt}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="help-block">At least one of Request Host, Source Port, or Request Path are required for each Target.</p>
|
|
||||||
<p class="help-block">If Request Host and/or Path are specified, connections to HTTP listening source ports will be routed to the appropriate target based on the request. For example, you could use this to send traffic for domain1.com to one service and domain2.com to a different service.</p>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,16 @@
|
||||||
{{#if listenersArray.length}}
|
{{#if listenersArray.length}}
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Source Port</th>
|
<th>Source Port*</th>
|
||||||
<th width="30"></th>
|
<th width="30"></th>
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<th>Default Target Port</th>
|
||||||
|
<th width="30"></th>
|
||||||
|
{{/if}}
|
||||||
<th width="100">Access</th>
|
<th width="100">Access</th>
|
||||||
<th width="30"></th>
|
<th width="30"></th>
|
||||||
<th width="60">Protocol</th>
|
<th width="60">Protocol</th>
|
||||||
<th width="30"></th>
|
<th width="30"></th>
|
||||||
<th width="100">Algorithm</th>
|
|
||||||
<th width="40"> </th>
|
<th width="40"> </th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -19,6 +22,12 @@
|
||||||
{{#if listener.id}}
|
{{#if listener.id}}
|
||||||
<td>{{listener.sourcePort}}</td>
|
<td>{{listener.sourcePort}}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<td>
|
||||||
|
{{listener.targetPort}}
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
{{/if}}
|
||||||
<td>{{if listener.isPublic "Public" "Internal"}}</td>
|
<td>{{if listener.isPublic "Public" "Internal"}}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>{{listener.sourceProtocol}}</td>
|
<td>{{listener.sourceProtocol}}</td>
|
||||||
|
|
@ -32,6 +41,12 @@
|
||||||
{{input type="text" classNames="form-control lb-listener-source-port input-sm" min="1" max="65535" step="1" value=listener.sourcePort placeholder="e.g. 80"}}
|
{{input type="text" classNames="form-control lb-listener-source-port input-sm" min="1" max="65535" step="1" value=listener.sourcePort placeholder="e.g. 80"}}
|
||||||
</td>
|
</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
{{#if isAdvanced}}
|
||||||
|
<td>
|
||||||
|
{{input type="text" classNames="form-control lb-listener-target-port input-sm" min="1" max="65535" step="1" value=listener.targetPort placeholder="e.g. 80"}}
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
|
{{/if}}
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown" aria-expanded="false">{{if listener.isPublic "Public" "Internal"}} <span class="caret"></span></button>
|
<button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown" aria-expanded="false">{{if listener.isPublic "Public" "Internal"}} <span class="caret"></span></button>
|
||||||
|
|
@ -61,9 +76,6 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>
|
|
||||||
<div class="form-control-static input-sm">Round Robin</div>
|
|
||||||
</td>
|
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button {{action "removeListener" listener}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
<button {{action "removeListener" listener}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ui",
|
"name": "ui",
|
||||||
"version": "0.34.0",
|
"version": "0.35.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "doc",
|
"doc": "doc",
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,31 @@ test('it works', function(assert) {
|
||||||
|
|
||||||
var data = [
|
var data = [
|
||||||
// New Format
|
// New Format
|
||||||
{str: "example.com:80/path:81", parsed: {hostname: 'example.com', srcPort: 80, path: '/path', dstPort: 81}},
|
{str: "example.com:80/path=81", parsed: {hostname: 'example.com', srcPort: 80, path: '/path', dstPort: 81}},
|
||||||
{str: "example.com:80:81", parsed: {hostname: 'example.com', srcPort: 80, path: null, dstPort: 81}},
|
{str: "example.com:80=81", parsed: {hostname: 'example.com', srcPort: 80, path: null, dstPort: 81}},
|
||||||
{str: "example.com/path:81", parsed: {hostname: 'example.com', srcPort: null, path: '/path', dstPort: 81}},
|
{str: "example.com/path=81", parsed: {hostname: 'example.com', srcPort: null, path: '/path', dstPort: 81}},
|
||||||
{str: "example.com:81", parsed: {hostname: 'example.com', srcPort: null, path: null, dstPort: 81}},
|
{str: "example.com=81", parsed: {hostname: 'example.com', srcPort: null, path: null, dstPort: 81}},
|
||||||
{str: "80/path:81", parsed: {hostname: null, srcPort: 80, path: '/path', dstPort: 81}},
|
{str: "80/path=81", parsed: {hostname: null, srcPort: 80, path: '/path', dstPort: 81}},
|
||||||
{str: "80:81", parsed: {hostname: null, srcPort: 80, path: null, dstPort: 81}},
|
{str: "80=81", parsed: {hostname: null, srcPort: 80, path: null, dstPort: 81}},
|
||||||
{str: "/path:81", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}},
|
{str: "/path=81", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}},
|
||||||
//{"81", Invalid, but symmetry.. parsed: {hostname: null, srcPort: null, path: null, dstPort: 81}},
|
{str: "81", parsed: {hostname: null, srcPort: null, path: null, dstPort: 81}},
|
||||||
|
{str: "example.com:80/path", parsed: {hostname: 'example.com', srcPort: 80, path: '/path', dstPort: null}},
|
||||||
|
{str: "example.com:80", parsed: {hostname: 'example.com', srcPort: 80, path: null, dstPort: null}},
|
||||||
|
{str: "example.com/path", parsed: {hostname: 'example.com', srcPort: null, path: '/path', dstPort: null}},
|
||||||
|
{str: "example.com", parsed: {hostname: 'example.com', srcPort: null, path: null, dstPort: null}},
|
||||||
|
{str: "80/path", parsed: {hostname: null, srcPort: 80, path: '/path', dstPort: null}},
|
||||||
|
// {str: "80", Invalid, == dstPort parsed: {hostname: null, srcPort: 80, path: null, dstPort: null}},
|
||||||
|
{str: "/path", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: null}},
|
||||||
|
// {"", Invalid, but symmetry... parsed: {hostname: null, srcPort: null, path: null, dstPort: null}},
|
||||||
|
|
||||||
// Old format
|
// Old format
|
||||||
{str: "81:example.com/path", parsed: {hostname: 'example.com', srcPort: null, path: '/path', dstPort: 81}, expected: "example.com/path:81"},
|
{str: "81:example.com/path", parsed: {hostname: 'example.com', srcPort: null, path: '/path', dstPort: 81}, expected: "example.com/path=81"},
|
||||||
{str: "81:example.com", parsed: {hostname: 'example.com', srcPort: null, path: null, dstPort: 81}, expected: "example.com:81"},
|
{str: "81:example.com", parsed: {hostname: 'example.com', srcPort: null, path: null, dstPort: 81}, expected: "example.com=81"},
|
||||||
{str: "81:/path", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}, expected: "/path:81"},
|
{str: "81:/path", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}, expected: "/path=81"},
|
||||||
|
|
||||||
// Invalid
|
// Invalid
|
||||||
{str: "purplemonkeydishwasher", parsed: null},
|
// {str: ":81", parsed: null},
|
||||||
{str: "81", parsed: null},
|
// {str: "example.com::81", parsed: null},
|
||||||
{str: ":81", parsed: null},
|
|
||||||
{str: "example.com::81", parsed: null},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
data.forEach(function(obj) {
|
data.forEach(function(obj) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue