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);
|
||||
});
|
||||
|
||||
return out.sort().uniq();
|
||||
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||
}.property('allHosts.@each.labels'),
|
||||
|
||||
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'),
|
||||
|
||||
allContainers: function() {
|
||||
|
|
@ -243,7 +243,7 @@ export default Ember.Component.extend({
|
|||
out.pushObjects(keys);
|
||||
});
|
||||
|
||||
return out.sort().uniq();
|
||||
return out.map((key) => { return (key||'').toLowerCase(); }).sort().uniq();
|
||||
}.property('allContainers.@each.labels'),
|
||||
|
||||
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'),
|
||||
|
||||
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'),
|
||||
|
||||
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'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<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-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>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,105 +1,48 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
// New Format: [hostname][:srcPort][/path]:dstPort
|
||||
// New Format: [hostname][:srcPort][/path][=dstPort]
|
||||
// Older format: dstPort:[hostname][/path]
|
||||
export function parseTarget(str) {
|
||||
var srcPort = null, dstPort = null, hostname = null, path = null;
|
||||
var idx;
|
||||
str = str.trim();
|
||||
|
||||
var parts = str.split(':');
|
||||
if ( parts.length === 2 )
|
||||
var match;
|
||||
if ( match = str.match(/^(\d+)$/) )
|
||||
{
|
||||
if ( !parts[0].length || !parts[1].length)
|
||||
{
|
||||
// Invalid: ":something" or "something:"
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// New Format: just a dstPort
|
||||
hostname = null;
|
||||
srcPort = null;
|
||||
path = null;
|
||||
dstPort = parseInt(match[1], 10);
|
||||
}
|
||||
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"
|
||||
return 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;
|
||||
// It's a port
|
||||
hostname = null;
|
||||
srcPort = parseInt(match[1], 10) || null;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcPort = parseInt(parts[1].substr(0,idx), 10);
|
||||
path = parts[1].substr(idx);
|
||||
hostname = match[1] || null;
|
||||
srcPort = parseInt(match[3], 10) || null;
|
||||
}
|
||||
|
||||
dstPort = parseInt(match[6], 10) || null;
|
||||
path = match[4] || null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -117,18 +60,24 @@ export function stringifyTarget(tgt) {
|
|||
var hostname = Ember.get(tgt,'hostname');
|
||||
var path = Ember.get(tgt,'path');
|
||||
|
||||
// New Format: [hostname][:srcPort][/path]:dstPort
|
||||
if ( hostname || srcPort || path )
|
||||
// New Format: [hostname][:srcPort][/path][=dstPort]
|
||||
if ( hostname || path || dstPort )
|
||||
{
|
||||
var str = hostname || '';
|
||||
if ( 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;
|
||||
}
|
||||
|
|
@ -140,8 +89,25 @@ export function stringifyTarget(tgt) {
|
|||
|
||||
|
||||
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,
|
||||
initTargets: function(service) {
|
||||
this.set('isAdvanced', false);
|
||||
|
||||
var out = [];
|
||||
var existing = null;
|
||||
if ( service )
|
||||
|
|
@ -156,8 +122,14 @@ export default Ember.Mixin.create({
|
|||
var obj = parseTarget(str);
|
||||
if ( obj )
|
||||
{
|
||||
if ( obj.get('hostname') || obj.get('srcPort') || obj.get('path') || obj.get('dstPort') )
|
||||
{
|
||||
this.set('isAdvanced', true);
|
||||
}
|
||||
|
||||
obj.setProperties({
|
||||
isService: true,
|
||||
isAdvanced: false,
|
||||
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);
|
||||
},
|
||||
|
||||
targetResources: function() {
|
||||
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 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 Util from 'ui/utils/util';
|
||||
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'],
|
||||
queryParams: ['tab','hostId','advanced'],
|
||||
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',
|
||||
isPublic: true,
|
||||
sourcePort: '',
|
||||
sourceProtocol: 'tcp',
|
||||
sourceProtocol: 'http',
|
||||
targetPort: '',
|
||||
targetProtocol: 'tcp',
|
||||
targetProtocol: 'http',
|
||||
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 EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
||||
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'],
|
||||
environmentId: null,
|
||||
serviceId: null,
|
||||
|
|
@ -11,15 +12,8 @@ export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLo
|
|||
error: null,
|
||||
editing: false,
|
||||
primaryResource: Ember.computed.alias('model.balancer'),
|
||||
|
||||
actions: {
|
||||
addTargetService: function() {
|
||||
this.get('targetsArray').pushObject({isService: true, value: null, protocol: 'http'});
|
||||
},
|
||||
removeTarget: function(obj) {
|
||||
this.get('targetsArray').removeObject(obj);
|
||||
},
|
||||
},
|
||||
labelResource: Ember.computed.alias('model.launchConfig'),
|
||||
isGlobal: false,
|
||||
|
||||
initFields: function() {
|
||||
this._super();
|
||||
|
|
@ -56,19 +50,19 @@ export default Ember.ObjectController.extend(Cattle.LegacyNewOrEditMixin, EditLo
|
|||
}
|
||||
|
||||
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') )
|
||||
{
|
||||
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) {
|
||||
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') )
|
||||
{
|
||||
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 )
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export default Ember.Route.extend({
|
|||
resetController: function (controller, isExisting/*, transition*/) {
|
||||
if (isExisting)
|
||||
{
|
||||
controller.set('tab', 'listeners');
|
||||
controller.set('tab', 'stickiness');
|
||||
controller.set('stickiness', 'none');
|
||||
controller.set('environmentId', null);
|
||||
controller.set('serviceId', null);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,22 @@
|
|||
{{partial "loadbalancer/edit-targets"}}
|
||||
</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>
|
||||
|
||||
{{partial "form-divider"}}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import SelectTab from 'ui/mixins/select-tab';
|
|||
|
||||
export default Ember.View.extend(SelectTab, {
|
||||
actions: {
|
||||
addTargetService: addAction('addTargetService', '.lb-target'),
|
||||
addListener: addAction('addListener', '.lb-listener-source-port'),
|
||||
addTargetService: addAction('addTargetService', '.lb-target'),
|
||||
addListener: addAction('addListener', '.lb-listener-source-port'),
|
||||
addSchedulingRule: addAction('addSchedulingRule','.schedule-rule'),
|
||||
addLabel: addAction('addLabel', '.label-key'),
|
||||
},
|
||||
|
||||
didInsertElement: function() {
|
||||
|
|
|
|||
|
|
@ -30,32 +30,6 @@
|
|||
</div>
|
||||
|
||||
{{#unless isRequestedHost}}
|
||||
<div class="form-control-static">
|
||||
<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}}
|
||||
{{partial "container/scheduling-rules"}}
|
||||
{{/unless}}
|
||||
</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">
|
||||
<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>
|
||||
|
||||
{{#if userLabelArray.length}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<section class="text-center" style="padding: 0;">
|
||||
<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="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>
|
||||
</section>
|
||||
|
||||
|
|
@ -8,5 +10,21 @@
|
|||
<div class="section container-fluid tab-section" data-section="stickiness">
|
||||
{{partial "loadbalancer/edit-stickiness"}}
|
||||
</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>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,47 +2,26 @@
|
|||
<table class="grid fixed no-lines no-top-padding tight" style="margin-bottom: 0;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Request Host</th>
|
||||
<th width="10"> </th>
|
||||
<th>Source Port</th>
|
||||
<th width="10"> </th>
|
||||
<th>Request Path</th>
|
||||
<th width="30"> </th>
|
||||
{{#if isAdvanced}}
|
||||
<th>Request Host</th>
|
||||
<th width="10"> </th>
|
||||
<th>Source Port</th>
|
||||
<th width="10"> </th>
|
||||
<th>Request Path</th>
|
||||
<th width="30"> </th>
|
||||
{{/if}}
|
||||
<th>Target Service*</th>
|
||||
<th width="10"> </th>
|
||||
<th width="90">Target Port*</th>
|
||||
{{#if isAdvanced}}
|
||||
<th width="10"> </th>
|
||||
<th width="90">Target Port</th>
|
||||
{{/if}}
|
||||
<th width="30"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each targetsArray as |tgt|}}
|
||||
<tr>
|
||||
<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>
|
||||
{{loadbalancer-target-row tgt=tgt targetChoices=targetChoices remove="removeTarget" isAdvanced=isAdvanced}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</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}}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
{{#if listenersArray.length}}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Source Port</th>
|
||||
<th>Source Port*</th>
|
||||
<th width="30"></th>
|
||||
{{#if isAdvanced}}
|
||||
<th>Default Target Port</th>
|
||||
<th width="30"></th>
|
||||
{{/if}}
|
||||
<th width="100">Access</th>
|
||||
<th width="30"></th>
|
||||
<th width="60">Protocol</th>
|
||||
<th width="30"></th>
|
||||
<th width="100">Algorithm</th>
|
||||
<th width="40"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -19,6 +22,12 @@
|
|||
{{#if listener.id}}
|
||||
<td>{{listener.sourcePort}}</td>
|
||||
<td> </td>
|
||||
{{#if isAdvanced}}
|
||||
<td>
|
||||
{{listener.targetPort}}
|
||||
</td>
|
||||
<td> </td>
|
||||
{{/if}}
|
||||
<td>{{if listener.isPublic "Public" "Internal"}}</td>
|
||||
<td> </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"}}
|
||||
</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>
|
||||
<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>
|
||||
|
|
@ -61,9 +76,6 @@
|
|||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<div class="form-control-static input-sm">Round Robin</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<button {{action "removeListener" listener}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "0.34.0",
|
||||
"version": "0.35.0",
|
||||
"private": true,
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
|
|
|
|||
|
|
@ -14,25 +14,31 @@ test('it works', function(assert) {
|
|||
|
||||
var data = [
|
||||
// New Format
|
||||
{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/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: "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: "/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: "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/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: "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: "/path=81", parsed: {hostname: null, srcPort: null, path: '/path', 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
|
||||
{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:/path", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}, expected: "/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:/path", parsed: {hostname: null, srcPort: null, path: '/path', dstPort: 81}, expected: "/path=81"},
|
||||
|
||||
// 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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue