mirror of https://github.com/rancher/ui.git
Split listeners and portRules
This commit is contained in:
parent
e234dfb492
commit
5d3a22e29f
|
|
@ -15,11 +15,14 @@ export default Ember.Route.extend({
|
|||
let extInfo = parseExternalId(stack.get('externalId'));
|
||||
deps.push(catalog.fetchTemplate(extInfo.templateId, false));
|
||||
});
|
||||
return Ember.RSVP.all(deps).then((ahray) => {
|
||||
ahray.forEach((ary) => {
|
||||
let stck = stacks.findBy('externalIdInfo.templateId', ary.id);
|
||||
stck.catalogTemplateInfo = ary; // need that generica catalog icon
|
||||
|
||||
return Ember.RSVP.all(deps).then((templates) => {
|
||||
templates.forEach((template) => {
|
||||
stacks.filterBy('externalIdInfo.templateId', template.id).forEach((stack) => {
|
||||
Ember.set(stack,'catalogTemplateInfo',template);
|
||||
});
|
||||
});
|
||||
|
||||
return Ember.Object.create({
|
||||
stacks: stacks,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,14 +62,6 @@
|
|||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
{{else}}
|
||||
<div class="row">
|
||||
<div class="col span-6 offset-3 text-center pt-40 pb-40">
|
||||
<img style="width: 75%;" src="{{app.baseAssets}}assets/images/resources/container.svg"/>
|
||||
<a class="btn bg-link icon-btn mt-50" href="{{href-to 'balancers.new'}}">
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'nav.containers.addBalancer'}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{empty-table resource="container" newRoute="balancers.new" newTranslationKey="nav.containers.addBalancer"}}
|
||||
{{/if}}
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export default Ember.Controller.extend({
|
|||
|
||||
actions: {
|
||||
cancel() {
|
||||
this.transitionToRoute(this.get('parentRoute'));
|
||||
this.send('goToPrevious','apps-tab.index');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export default Ember.Component.extend(NewOrEdit, {
|
|||
isGlobal : null,
|
||||
isRequestedHost : null,
|
||||
upgradeOptions : null,
|
||||
hasUnsupportedPorts : false,
|
||||
|
||||
// Errors from components
|
||||
ruleErrors : null,
|
||||
|
|
@ -30,7 +29,6 @@ export default Ember.Component.extend(NewOrEdit, {
|
|||
this._super(...arguments);
|
||||
this.labelsChanged();
|
||||
this.get('service').initPorts();
|
||||
this.updatePorts();
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
@ -64,119 +62,6 @@ export default Ember.Component.extend(NewOrEdit, {
|
|||
return this.get('intl').t(k);
|
||||
}.property('intl.locale','needsUpgrade','isService','isVm','service.secondaryLaunchConfigs.length'),
|
||||
|
||||
// ----------------------------------
|
||||
// Ports
|
||||
// ----------------------------------
|
||||
updatePorts() {
|
||||
let rules = this.get('service.lbConfig.portRules')||[];
|
||||
let publish = [];
|
||||
let expose = [];
|
||||
|
||||
// Set ports and publish on the launch config
|
||||
rules.forEach((rule) => {
|
||||
// The inner one eliminates null/undefined, then the outer one
|
||||
// converts integers to string (so they can be re-parsed later)
|
||||
let srcStr = ((rule.get('sourcePort')||'')+'').trim();
|
||||
let src = parseInt(srcStr,10);
|
||||
if ( !src || src < 1 || src > 65535 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let entry = src+":"+src+"/"+rule.get('ipProtocol');
|
||||
if ( rule.get('access') === 'public' ) {
|
||||
// Source IP applies only to public rules
|
||||
let ip = rule.get('sourceIp');
|
||||
if ( ip ) {
|
||||
// IPv6
|
||||
if ( ip.indexOf(":") >= 0 && ip.substr(0,1) !== '[' ) {
|
||||
entry = '['+ip+']:' + entry;
|
||||
} else {
|
||||
entry = ip + ':' + entry;
|
||||
}
|
||||
}
|
||||
|
||||
publish.push(entry);
|
||||
} else {
|
||||
expose.push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
this.get('service.launchConfig').setProperties({
|
||||
ports: publish.uniq(),
|
||||
expose: expose.uniq(),
|
||||
});
|
||||
},
|
||||
|
||||
shouldUpdatePorts: function() {
|
||||
Ember.run.once(this,'updatePorts');
|
||||
}.observes('service.lbConfig.portRules.@each.{sourceIp,sourcePort,access,protocol}'),
|
||||
|
||||
|
||||
validateRules() {
|
||||
let intl = this.get('intl');
|
||||
let rules = this.get('service.lbConfig.portRules');
|
||||
let errors = [];
|
||||
let seen = {};
|
||||
|
||||
// Set ports and publish on the launch config
|
||||
// And also do a bunch of validation while we're here
|
||||
rules.forEach((rule) => {
|
||||
// The inner one eliminates null/undefined, then the outer one
|
||||
// converts integers to string (so they can be re-parsed later)
|
||||
let srcStr = ((rule.get('sourcePort')||'')+'').trim();
|
||||
let tgtStr = ((rule.get('targetPort')||'')+'').trim();
|
||||
|
||||
if ( !srcStr ) {
|
||||
errors.push(intl.t('newBalancer.error.noSourcePort'));
|
||||
return;
|
||||
}
|
||||
|
||||
let src = parseInt(srcStr,10);
|
||||
if ( !src || src < 1 || src > 65535 ) {
|
||||
errors.push(intl.t('newBalancer.error.invalidSourcePort', {num: srcStr}));
|
||||
} else if ( !tgtStr ) {
|
||||
tgtStr = srcStr;
|
||||
}
|
||||
|
||||
let tgt = parseInt(tgtStr,10);
|
||||
if ( !tgt || tgt < 1 || tgt > 65535 ) {
|
||||
errors.push(intl.t('newBalancer.error.invalidTargetPort', {num: tgtStr}));
|
||||
return;
|
||||
}
|
||||
|
||||
let sourceIp = rule.get('sourceIp');
|
||||
let key;
|
||||
if ( sourceIp ) {
|
||||
key = '['+sourceIp+']:' + src;
|
||||
} else {
|
||||
key = '[0.0.0.0]:' + src;
|
||||
}
|
||||
|
||||
let access = rule.get('access');
|
||||
let id = access + '-' + rule.get('protocol') + '-' + src;
|
||||
|
||||
if ( seen[key] ) {
|
||||
if ( seen[key] !== id ) {
|
||||
errors.push(intl.t('newBalancer.error.mixedPort', {num: src}));
|
||||
}
|
||||
} else {
|
||||
seen[key] = id;
|
||||
}
|
||||
|
||||
if ( !rule.get('serviceId') && !rule.get('selector') ) {
|
||||
errors.push(intl.t('newBalancer.error.noTarget'));
|
||||
}
|
||||
|
||||
// Make ports always numeric
|
||||
rule.setProperties({
|
||||
sourcePort: src,
|
||||
targetPort: tgt,
|
||||
});
|
||||
});
|
||||
|
||||
this.set('ruleErrors', errors);
|
||||
},
|
||||
|
||||
needsUpgrade: function() {
|
||||
function arrayToStr(map) {
|
||||
map = map || {};
|
||||
|
|
@ -278,8 +163,6 @@ export default Ember.Component.extend(NewOrEdit, {
|
|||
// Save
|
||||
// ----------------------------------
|
||||
willSave() {
|
||||
this.validateRules();
|
||||
|
||||
let ok = this._super(...arguments);
|
||||
if ( ok && !this.get('isUpgrade') ) {
|
||||
// Set the stack ID
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@
|
|||
</div>
|
||||
|
||||
<section class="horizontal-form container-fluid">
|
||||
{{form-balancer-rules
|
||||
{{form-balancer-listeners
|
||||
service=service
|
||||
errors=ruleErrors
|
||||
}}
|
||||
<hr/>
|
||||
</section>
|
||||
|
||||
{{container/form-scheduling
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
import Ember from 'ember';
|
||||
import { parsePortSpec } from 'ui/utils/parse-port';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
intl: Ember.inject.service(),
|
||||
|
||||
service: null,
|
||||
|
||||
ports: null,
|
||||
protocolChoices: null,
|
||||
showBackend: null,
|
||||
errors: null,
|
||||
|
||||
onInit: function() {
|
||||
let rules = this.get('service.lbConfig.portRules');
|
||||
let ports = [];
|
||||
|
||||
rules.forEach((rule) => {
|
||||
let kind = 'service';
|
||||
if ( !!rule.selector ) {
|
||||
kind= 'selector';
|
||||
} else if ( rule.instanceId ) {
|
||||
rule.kind = 'instance';
|
||||
}
|
||||
|
||||
rule.set('kind', kind);
|
||||
});
|
||||
|
||||
(this.get('service.launchConfig.ports')||[]).forEach((str) => {
|
||||
let parsed = parsePortSpec(str);
|
||||
let obj = Ember.Object.create({
|
||||
access: 'public',
|
||||
protocol: null,
|
||||
sourcePort: parsed.hostPort,
|
||||
sourceIp: parsed.hostIp,
|
||||
rules: [],
|
||||
});
|
||||
ports.push(obj);
|
||||
});
|
||||
|
||||
(this.get('service.launchConfig.expose')||[]).forEach((str) => {
|
||||
let parsed = parsePortSpec(str);
|
||||
let obj = Ember.Object.create({
|
||||
access: 'internal',
|
||||
protocol: null,
|
||||
sourcePort: parsed.hostPort,
|
||||
sourceIp: null,
|
||||
rules: [],
|
||||
});
|
||||
ports.push(obj);
|
||||
});
|
||||
|
||||
// Filter the rules into the right port
|
||||
ports.forEach((obj) => {
|
||||
obj.set('rules',rules.filter((x) => {
|
||||
return x.sourcePort === obj.sourcePort
|
||||
}));
|
||||
obj.set('protocol', obj.get('rules.firstObject.protocol')||'http');
|
||||
});
|
||||
|
||||
this.set('ports', ports);
|
||||
if ( ports.length === 0 ) {
|
||||
this.send('addPort');
|
||||
}
|
||||
|
||||
let protos = this.get('store').getById('schema','portrule').optionsFor('protocol');
|
||||
protos.removeObject('udp');
|
||||
protos.sort();
|
||||
this.set('protocolChoices', protos);
|
||||
|
||||
if ( this.get('showBackend') === null ) {
|
||||
let hasName = !!rules.findBy('backendName');
|
||||
this.set('showBackend', hasName);
|
||||
}
|
||||
}.on('init'),
|
||||
|
||||
shouldFlattenAndValidate: function() {
|
||||
Ember.run.once(this,'flattenAndValidate');
|
||||
}.observes('ports.@each.{sourcePort,protocol,access,sourceIp,rules}'),
|
||||
|
||||
flattenAndValidate() {
|
||||
let intl = this.get('intl');
|
||||
let ports = this.get('ports');
|
||||
let errors = [];
|
||||
let rules = [];
|
||||
let publish = [];
|
||||
let expose = [];
|
||||
let seen = {};
|
||||
|
||||
// Set ports and publish on the launch config
|
||||
// And also do a bunch of validation while we're here
|
||||
ports.forEach((port) => {
|
||||
// 1. Set expose/ports and ensure valid ports/protocols
|
||||
let srcStr = ((port.get('sourcePort')||'')+'').trim();
|
||||
if ( !srcStr ) {
|
||||
errors.push(intl.t('newBalancer.error.noSourcePort'));
|
||||
return;
|
||||
}
|
||||
|
||||
let src = parseInt(srcStr,10);
|
||||
if ( !src || src < 1 || src > 65535 ) {
|
||||
errors.push(intl.t('newBalancer.error.invalidSourcePort', {num: srcStr}));
|
||||
}
|
||||
|
||||
let sourceIp = port.get('sourceIp');
|
||||
let uniqueKey;
|
||||
if ( sourceIp ) {
|
||||
uniqueKey = '['+sourceIp+']:' + src;
|
||||
} else {
|
||||
uniqueKey = '[0.0.0.0]:' + src;
|
||||
}
|
||||
|
||||
let access = port.get('access');
|
||||
let protocol = port.get('protocol');
|
||||
let id = access + '-' + protocol + '-' + src;
|
||||
|
||||
if ( seen[uniqueKey] ) {
|
||||
if ( seen[uniqueKey] !== id ) {
|
||||
errors.push(intl.t('newBalancer.error.mixedPort', {num: src}));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
seen[uniqueKey] = id;
|
||||
}
|
||||
|
||||
let entry = src+":"+src+"/"+ ( protocol === 'udp' ? 'udp' : 'tcp');
|
||||
if ( access === 'public' ) {
|
||||
// Source IP applies only to public rules
|
||||
if ( sourceIp ) {
|
||||
// IPv6
|
||||
if ( sourceIp.indexOf(":") >= 0 && sourceIp.substr(0,1) !== '[' ) {
|
||||
entry = '['+sourceIp+']:' + entry;
|
||||
} else {
|
||||
entry = sourceIp + ':' + entry;
|
||||
}
|
||||
}
|
||||
|
||||
publish.push(entry);
|
||||
} else {
|
||||
expose.push(entry);
|
||||
}
|
||||
|
||||
// 2. Set rules
|
||||
port.get('rules').forEach((rule) => {
|
||||
// The inner one eliminates null/undefined, then the outer one
|
||||
// converts integers to string (so they can be re-parsed later)
|
||||
let tgtStr = ((rule.get('targetPort')||'')+'').trim();
|
||||
if ( !tgtStr ) {
|
||||
errors.push(intl.t('newBalancer.error.noTargetPort'));
|
||||
return;
|
||||
}
|
||||
|
||||
let tgt = parseInt(tgtStr,10);
|
||||
if ( !tgt || tgt < 1 || tgt > 65535 ) {
|
||||
errors.push(intl.t('newBalancer.error.invalidTargetPort', {num: tgtStr}));
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !rule.get('serviceId') && !rule.get('instanceId') && !rule.get('selector') ) {
|
||||
errors.push(intl.t('newBalancer.error.noTarget'));
|
||||
}
|
||||
|
||||
// Make ports always numeric
|
||||
rule.setProperties({
|
||||
protocol: protocol,
|
||||
sourcePort: src,
|
||||
targetPort: tgt,
|
||||
});
|
||||
|
||||
rules.push(rule);
|
||||
});
|
||||
});
|
||||
|
||||
this.setProperties({
|
||||
'service.launchConfig.ports': publish.uniq(),
|
||||
'service.launchConfig.expose': expose.uniq(),
|
||||
'errors': errors.uniq(),
|
||||
'service.lbConfig.portRules': rules.sortBy('priority')
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
addPort() {
|
||||
let port = Ember.Object.create({
|
||||
access: 'public',
|
||||
protocol: 'http',
|
||||
port: null,
|
||||
sourceIp: null,
|
||||
rules: [],
|
||||
});
|
||||
|
||||
this.get('ports').pushObject(port);
|
||||
},
|
||||
|
||||
removePort(port) {
|
||||
this.get('ports').removeObject(port);
|
||||
},
|
||||
|
||||
showBackend() {
|
||||
this.set('showBackend', true);
|
||||
},
|
||||
|
||||
rulesChanged() {
|
||||
this.shouldFlattenAndValidate();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<div>
|
||||
<label>{{t 'formBalancerListeners.label'}}</label>
|
||||
<button class="btn bg-link icon-btn ml-20" {{action "addPort"}}>
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'formBalancerListeners.addPortLabel'}}</span>
|
||||
</button>
|
||||
{{#unless showBackend}}
|
||||
<div class="pull-right clearfix">
|
||||
<button class="btn bg-transparent p-0 text-small text-right" {{action "showBackend"}}>
|
||||
{{t 'formBalancerListeners.showBackendLabel'}}
|
||||
</button>
|
||||
</div>
|
||||
{{/unless}}
|
||||
<hr/>
|
||||
<p class="text-info">
|
||||
{{t 'formBalancerListeners.help'}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{#each ports as |port|}}
|
||||
<div class="box mb-10">
|
||||
<div class="row">
|
||||
<div class="col span-3">
|
||||
<label class="acc-label">{{t 'formBalancerListeners.sourcePort.label'}}{{field-required}}</label>
|
||||
{{input-integer class="form-control input-sm" min="1" max="65535" value=port.sourcePort placeholder=(t 'formBalancerListeners.sourcePort.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-3">
|
||||
<label class="acc-label">{{t 'formBalancerListeners.protocol.label'}}</label>
|
||||
<select class="form-control input-sm" onchange={{action (mut port.protocol) value="target.value"}}>
|
||||
{{#each protocolChoices as |proto|}}
|
||||
<option value={{proto}} selected={{eq port.protocol proto}}>{{upper-case proto}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col span-3">
|
||||
<label class="acc-label">{{t 'formBalancerListeners.access.label'}}</label>
|
||||
<select class="form-control input-sm" onchange={{action (mut port.access) value="target.value"}}>
|
||||
<option value="public" selected={{eq port.access "public"}}>{{t 'formBalancerListeners.access.public'}}</option>
|
||||
<option value="internal" selected={{eq port.access "internal"}}>{{t 'formBalancerListeners.access.internal'}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col span-3">
|
||||
<label class="acc-label">{{t 'formBalancerListeners.sourceIp.label'}}</label>
|
||||
{{#if (eq port.access "public")}}
|
||||
{{input type="text" class="form-control input-sm" value=port.sourceIp placeholder=(t 'formBalancerListeners.sourceIp.placeholder')}}
|
||||
{{else}}
|
||||
<div class="text-muted form-control-static">{{t 'generic.na'}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
{{form-balancer-rules
|
||||
rules=port.rules
|
||||
protocol=port.protocol
|
||||
rulesChanged=(action 'rulesChanged')
|
||||
singleTarget=false
|
||||
showBackend=showBackend
|
||||
editing=true
|
||||
}}
|
||||
<div class="clearfix">
|
||||
<button class="btn bg-transparent p-0 text-small pull-right" {{action "removePort" port}}>
|
||||
{{t 'formBalancerListeners.removePortLabel'}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="p-20">{{t 'formBalancerListeners.noRules'}}</div>
|
||||
{{/each}}
|
||||
|
|
@ -1,56 +1,19 @@
|
|||
import Ember from 'ember';
|
||||
import { parsePortSpec } from 'ui/utils/parse-port';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
intl: Ember.inject.service(),
|
||||
|
||||
service: null,
|
||||
ruleType: 'portRule',
|
||||
showListeners: Ember.computed.equal('ruleType','portRule'),
|
||||
|
||||
rules: null,
|
||||
protocolChoices: null,
|
||||
showBackend: null,
|
||||
showIp: null,
|
||||
singleTarget: true,
|
||||
protocol: null,
|
||||
editing: true,
|
||||
|
||||
onInit: function() {
|
||||
let rules = this.get('service.lbConfig.portRules');
|
||||
if ( !rules ) {
|
||||
rules = [];
|
||||
this.set('service.lbConfig.portRules', rules);
|
||||
}
|
||||
ruleType: 'portRule',
|
||||
|
||||
rules.forEach((rule) => {
|
||||
rule.isSelector = !!rule.selector;
|
||||
});
|
||||
|
||||
this.set('rules', rules);
|
||||
if ( rules.length === 0 ) {
|
||||
this.send('addRule');
|
||||
}
|
||||
|
||||
let protos = this.get('store').getById('schema','portrule').optionsFor('protocol');
|
||||
protos.removeObject('udp');
|
||||
protos.sort();
|
||||
this.set('protocolChoices', protos);
|
||||
|
||||
if ( this.get('showBackend') === null ) {
|
||||
let hasName = !!rules.findBy('backendName');
|
||||
this.set('showBackend', hasName);
|
||||
}
|
||||
|
||||
if ( this.get('showIp') === null ) {
|
||||
this.get('service.launchConfig.ports').forEach((port) => {
|
||||
let parsed = parsePortSpec(port,'tcp');
|
||||
if ( parsed.hostIp ) {
|
||||
this.set('showIp', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}.on('init'),
|
||||
rulesChanged: function() {
|
||||
this.sendAction('rulesChanged');
|
||||
}.observes('rules.@each.{hostname,path,kind,instanceId,serviceId,selector,targetPort,backendName}'),
|
||||
|
||||
actions: {
|
||||
addRule(isSelector) {
|
||||
addRule(kind) {
|
||||
let max = 0;
|
||||
let rules = this.get('rules');
|
||||
rules.forEach((rule) => {
|
||||
|
|
@ -59,9 +22,8 @@ export default Ember.Component.extend({
|
|||
|
||||
rules.pushObject(this.get('store').createRecord({
|
||||
type: this.get('ruleType'),
|
||||
access: 'public',
|
||||
isSelector: isSelector,
|
||||
protocol: 'http',
|
||||
kind: kind,
|
||||
protocol: this.get('protocol'),
|
||||
priority: max+1,
|
||||
}));
|
||||
},
|
||||
|
|
@ -93,16 +55,15 @@ export default Ember.Component.extend({
|
|||
removeRule(rule) {
|
||||
this.get('rules').removeObject(rule);
|
||||
},
|
||||
|
||||
showBackend() {
|
||||
this.set('showBackend', true);
|
||||
},
|
||||
|
||||
showIp() {
|
||||
this.set('showIp', true);
|
||||
},
|
||||
},
|
||||
|
||||
protocolChanged: function() {
|
||||
let protocol = this.get('protocol');
|
||||
this.get('rules').forEach((rule) => {
|
||||
rule.set('protocol', protocol);
|
||||
});
|
||||
}.observes('protocol'),
|
||||
|
||||
updatePriorities() {
|
||||
let pri = 1;
|
||||
this.get('rules').forEach((rule) => {
|
||||
|
|
@ -110,27 +71,4 @@ export default Ember.Component.extend({
|
|||
pri++;
|
||||
});
|
||||
},
|
||||
|
||||
minPriority: function() {
|
||||
let val = null;
|
||||
this.get('rules').forEach((rule) => {
|
||||
let cur = rule.get('priority');
|
||||
if ( val === null ) {
|
||||
val = cur;
|
||||
} else {
|
||||
val = Math.min(val, cur);
|
||||
}
|
||||
});
|
||||
|
||||
return val;
|
||||
}.property('rules.@each.priority'),
|
||||
|
||||
maxPriority: function() {
|
||||
let val = 0;
|
||||
this.get('rules').forEach((rule) => {
|
||||
val = Math.max(val, rule.get('priority'));
|
||||
});
|
||||
|
||||
return val;
|
||||
}.property('rules.@each.priority'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,159 +1,121 @@
|
|||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'formBalancerRules.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-8">
|
||||
{{#unless editing}}
|
||||
<button class="btn bg-link icon-btn" {{action "addRule" false}}>
|
||||
<div class="clearfix">
|
||||
<label class="acc-label">{{t 'formBalancerRules.label'}}</label>
|
||||
{{#if editing}}
|
||||
{{#if singleTarget}}
|
||||
<button class="btn bg-link icon-btn" {{action "addRule" "target"}}>
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'formBalancerRules.addTargetLabel'}}</span>
|
||||
</button>
|
||||
{{else}}
|
||||
<button class="btn bg-link icon-btn" {{action "addRule" "service"}}>
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'formBalancerRules.addServiceLabel'}}</span>
|
||||
</button>
|
||||
<button class="btn bg-link icon-btn pl-20" {{action "addRule" true}}>
|
||||
<button class="btn bg-link icon-btn ml-20" {{action "addRule" "instance"}}>
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'formBalancerRules.addInstanceLabel'}}</span>
|
||||
</button>
|
||||
<button class="btn bg-link icon-btn ml-20" {{action "addRule" "selector"}}>
|
||||
<span class="darken"><i class="icon icon-plus text-small"></i></span>
|
||||
<span>{{t 'formBalancerRules.addSelectorLabel'}}</span>
|
||||
</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="">
|
||||
{{#if rules.length}}
|
||||
<table class="grid fixed no-lines no-top-padding tight mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
{{#if showListeners}}
|
||||
<th width="30"> </th>
|
||||
<th width="100">{{t 'formBalancerRules.access.label'}}{{field-required}}</th>
|
||||
{{#if showIp}}
|
||||
<th>{{t 'formBalancerRules.sourceIp.label'}}</th>
|
||||
{{/if}}
|
||||
<th width="100">{{t 'formBalancerRules.protocol.label'}}{{field-required}}</th>
|
||||
<th class="divided">{{t 'formBalancerRules.hostname.label'}}</th>
|
||||
<th width="100">{{t 'formBalancerRules.sourcePort.label'}}{{field-required}}</th>
|
||||
<th>{{t 'formBalancerRules.path.label'}}</th>
|
||||
<th class="divided">{{t 'formBalancerRules.target'}}{{field-required}}</th>
|
||||
<th width="100">{{t 'formBalancerRules.targetPort.label'}}{{field-required}}</th>
|
||||
{{else}}
|
||||
<th>{{t 'formBalancerRules.hostname.label'}}</th>
|
||||
<th>{{t 'formBalancerRules.path.label'}}</th>
|
||||
<th width="100" class="divided">{{t 'formBalancerRules.targetPort.label'}}{{field-required}}</th>
|
||||
{{/if}}
|
||||
{{#if showBackend}}
|
||||
<th class="divided">{{t 'formBalancerRules.backendName.label'}}</th>
|
||||
{{/if}}
|
||||
{{#if showListeners}}
|
||||
<th width="40"> </th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each rules as |rule idx|}}
|
||||
<tr>
|
||||
{{#if showListeners}}
|
||||
<td data-title="{{t 'formBalancerRules.priority.label'}}">
|
||||
<button class="btn bg-default btn-xs" {{action "moveUp" rule}} disabled={{eq rule.priority minPriority}}>
|
||||
<i class="icon icon-chevron-up"></i>
|
||||
</button>
|
||||
<button class="btn bg-default btn-xs" {{action "moveDown" rule}} disabled={{eq rule.priority maxPriority}}>
|
||||
<i class="icon icon-chevron-down"></i>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.access.label'}}">
|
||||
<select class="form-control input-sm" onchange={{action (mut rule.access) value="target.value"}}>
|
||||
<option value="public" selected={{eq rule.access "public"}}>{{t 'formBalancerRules.access.public'}}</option>
|
||||
<option value="internal" selected={{eq rule.access "internal"}}>{{t 'formBalancerRules.access.internal'}}</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
{{#if showIp}}
|
||||
<td data-title="{{t 'formBalancerRules.sourceIp.label'}}">
|
||||
{{#if (eq rule.access "public")}}
|
||||
{{input type="text" class="form-control input-sm" value=rule.sourceIp placeholder=(t 'formBalancerRules.sourceIp.placeholder')}}
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'generic.na'}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.protocol.label'}}">
|
||||
<select class="form-control input-sm" onchange={{action (mut rule.protocol) value="target.value"}}>
|
||||
{{#each protocolChoices as |proto|}}
|
||||
<option value={{proto}} selected={{eq rule.protocol proto}}>{{upper-case proto}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<td class="divided" data-title="{{t 'formBalancerRules.hostname.label'}}">
|
||||
{{#if rule.canHostname}}
|
||||
{{input type="text" class="form-control input-sm" value=rule.hostname placeholder=(t 'formBalancerRules.hostname.placeholder')}}
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'generic.na'}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if showListeners}}
|
||||
<td data-title="{{t 'formBalancerRules.sourcePort.label'}}">
|
||||
{{input-integer class="form-control input-sm" min="1" max="65535" value=rule.sourcePort placeholder=(t 'formBalancerRules.sourcePort.placeholder')}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.path.label'}}">
|
||||
{{#if rule.canPath}}
|
||||
{{input type="text" class="form-control input-sm" value=rule.path placeholder=(t 'formBalancerRules.path.placeholder')}}
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'generic.na'}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if showListeners}}
|
||||
<td class="divided" data-title="{{t (if rule.isSelector 'formBalancerRules.selector.label' 'formBalancerRules.serviceId.label')}}">
|
||||
{{#if rule.isSelector}}
|
||||
{{input type="text" class="form-control input-sm" value=rule.selector placeholder=(t 'formBalancerRules.selector.placeholder')}}
|
||||
{{else}}
|
||||
{{schema/input-service selectClass="form-control input-sm" canBalanceTo=true selected=rule.serviceId}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.targetPort.label'}}">
|
||||
{{input-integer class="form-control input-sm" min="1" max="65535" value=rule.targetPort placeholder=(t 'formBalancerRules.targetPort.placeholder')}}
|
||||
</td>
|
||||
|
||||
{{#if showBackend}}
|
||||
<td class="divided" data-title="{{t 'formBalancerRules.backendName.label'}}">
|
||||
{{input type="text" class="form-control input-sm" value=rule.backendName placeholder=(t 'formBalancerRules.backendName.placeholder')}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
{{#if showListeners}}
|
||||
<td class="text-right">
|
||||
<button class="btn bg-primary btn-sm" {{action "removeRule" rule}}><i class="icon icon-minus"/><span class="sr-only">{{t 'generic.remove'}}</span></button>
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="text-info">
|
||||
{{t 'formBalancerRules.help.prefix'}}
|
||||
{{#unless showBackend}}
|
||||
<a href="#" {{action "showBackend"}}>
|
||||
{{t 'formBalancerRules.help.showBackendLink'}}
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{#unless showIp}}
|
||||
<a href="#" {{action "showIp"}}>
|
||||
{{t 'formBalancerRules.help.showIpLink'}}
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{t 'formBalancerRules.help.suffix'}}
|
||||
</p>
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'formBalancerRules.noRules'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if rules.length}}
|
||||
<table class="grid fixed no-lines no-top-padding mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
{{#unless singleTarget}}
|
||||
<th width="30"> </th>
|
||||
{{/unless}}
|
||||
|
||||
<th class="divided">{{t 'formBalancerRules.hostname.label'}}</th>
|
||||
|
||||
<th>{{t 'formBalancerRules.path.label'}}</th>
|
||||
|
||||
{{#if singleTarget}}
|
||||
<th width="30"> </th>
|
||||
{{else}}
|
||||
<th class="divided">{{t 'formBalancerRules.target'}}{{field-required}}</th>
|
||||
{{/if}}
|
||||
|
||||
<th width="100" class="divided">{{t 'formBalancerRules.targetPort.label'}}{{field-required}}</th>
|
||||
|
||||
{{#if showBackend}}
|
||||
<th class="divided">{{t 'formBalancerRules.backendName.label'}}</th>
|
||||
{{/if}}
|
||||
|
||||
{{#if editing}}
|
||||
<th width="40"> </th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each rules as |rule idx|}}
|
||||
<tr>
|
||||
{{#unless singleTarget}}
|
||||
<td data-title="{{t 'formBalancerRules.priority.label'}}">
|
||||
<button class="btn bg-default btn-xs" {{action "moveUp" rule}} disabled={{eq idx 0}}>
|
||||
<i class="icon icon-chevron-up"></i>
|
||||
</button>
|
||||
<button class="btn bg-default btn-xs" {{action "moveDown" rule}} disabled={{eq idx (sub rules.length 1)}}>
|
||||
<i class="icon icon-chevron-down"></i>
|
||||
</button>
|
||||
</td>
|
||||
{{/unless}}
|
||||
|
||||
<td class="divided" data-title="{{t 'formBalancerRules.hostname.label'}}">
|
||||
{{#if rule.canHostname}}
|
||||
{{input type="text" class="input-sm" value=rule.hostname placeholder=(t 'formBalancerRules.hostname.placeholder')}}
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'generic.na'}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.path.label'}}">
|
||||
{{#if rule.canPath}}
|
||||
{{input type="text" class="input-sm" value=rule.path placeholder=(t 'formBalancerRules.path.placeholder')}}
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'generic.na'}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if singleTarget}}
|
||||
<td> </td>
|
||||
{{else}}
|
||||
<td class="divided" data-title="{{t (concat-str 'formBalancerRules' rule.kind 'label' character='.')}}">
|
||||
{{#if (eq rule.kind 'selector')}}
|
||||
{{input type="text" class="input-sm" value=rule.selector placeholder=(t 'formBalancerRules.selector.placeholder')}}
|
||||
{{else if (eq rule.kind 'instance')}}
|
||||
{{schema/input-container selectClass="input-sm" selected=rule.instanceId}}
|
||||
{{else}}
|
||||
{{schema/input-service selectClass="input-sm" canBalanceTo=true selected=rule.serviceId}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<td data-title="{{t 'formBalancerRules.targetPort.label'}}">
|
||||
{{input-integer class="input-sm" min="1" max="65535" value=rule.targetPort placeholder=(t 'formBalancerRules.targetPort.placeholder')}}
|
||||
</td>
|
||||
|
||||
{{#if showBackend}}
|
||||
<td class="divided" data-title="{{t 'formBalancerRules.backendName.label'}}">
|
||||
{{input type="text" class="input-sm" value=rule.backendName placeholder=(t 'formBalancerRules.backendName.placeholder')}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
{{#if editing}}
|
||||
<td class="text-right">
|
||||
<button class="btn bg-primary btn-sm" {{action "removeRule" rule}}><i class="icon icon-minus"/><span class="sr-only">{{t 'generic.remove'}}</span></button>
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<span class="text-muted">{{t 'formBalancerRules.noRules'}}</span>
|
||||
{{/if}}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ export default Ember.Component.extend({
|
|||
count++;
|
||||
}
|
||||
|
||||
if ( this.get('lbConfig.needsCertificate') && !count ) {
|
||||
k = STATUS.INCOMPLETE;
|
||||
}
|
||||
|
||||
if ( count ) {
|
||||
k = STATUS.COUNTCONFIGURED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
allContainers : Ember.inject.service(),
|
||||
|
||||
selected: null, // Selected service ID
|
||||
exclude: null, // ID or array of IDs to exclude from list
|
||||
|
||||
// For use as a catalog question
|
||||
field: null, // Read default from a schema resourceField
|
||||
value: null, // stackName/serviceName string output
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
let def = this.get('field.default');
|
||||
if ( def && !this.get('selected') ) {
|
||||
|
||||
let match = this.get('allContainers.list').findBy('name', def);
|
||||
this.set('selected', match || null);
|
||||
}
|
||||
},
|
||||
|
||||
grouped: function() {
|
||||
let list = this.get('allContainers.list');
|
||||
|
||||
let exclude = this.get('exclude');
|
||||
if ( exclude ) {
|
||||
if ( !Ember.isArray(exclude) ) {
|
||||
exclude = [exclude];
|
||||
}
|
||||
|
||||
list = list.filter(x => !exclude.includes(x.id));
|
||||
}
|
||||
|
||||
return this.get('allContainers').group(list);
|
||||
}.property('allContainers.list.[]','canBalanceTo','canHaveContainers'),
|
||||
|
||||
selectedChanged: function() {
|
||||
let id = this.get('selected');
|
||||
let str = null;
|
||||
|
||||
if ( id ) {
|
||||
let service = this.get('allContainers').byId(id);
|
||||
if ( service ) {
|
||||
str = service.get('stack.name') + '/' + service.get('name');
|
||||
}
|
||||
}
|
||||
|
||||
this.set('value', str);
|
||||
}.observes('selected'),
|
||||
});
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<select class="{{selectClass}}" onchange={{action (mut selected) value="target.value"}}>
|
||||
<option selected={{eq selected null}}>{{t 'schema.inputContainer.prompt'}}</option>
|
||||
{{#each-in grouped as |group list|}}
|
||||
<optgroup label={{group}}>
|
||||
{{#each list as |svc|}}
|
||||
<option selected={{eq selected svc.id}} value={{svc.id}}>{{svc.name}}</option>
|
||||
{{/each}}
|
||||
</optgroup>
|
||||
{{/each-in}}
|
||||
</select>
|
||||
|
|
@ -70,6 +70,5 @@ export default Ember.Component.extend({
|
|||
}
|
||||
|
||||
this.set('value', str);
|
||||
console.log('val', str);
|
||||
}.observes('selected'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ export default Ember.Mixin.create({
|
|||
// let version = instance.get('version')||"";
|
||||
|
||||
let k8sName = (instance.get('labels')||{})[C.LABEL.K8S_POD_NAMESPACE] || '';
|
||||
let stackId = instance.get('primaryStack.id') || '';
|
||||
let stackName = instance.get('primaryStack.displayName') || '';
|
||||
let stackId = instance.get('stack.id') || '';
|
||||
let stackName = instance.get('stack.displayName') || '';
|
||||
|
||||
let groupId, groupName;
|
||||
if ( k8sName ) {
|
||||
|
|
|
|||
|
|
@ -30,17 +30,13 @@ var Container = Instance.extend({
|
|||
primaryHost : denormalizeId('hostId'),
|
||||
services : denormalizeIdArray('serviceIds'),
|
||||
primaryService : Ember.computed.alias('services.firstObject'),
|
||||
primaryStack : Ember.computed.alias('primaryService.stack'),
|
||||
referencedStack : denormalizeId('stackId'),
|
||||
referencedService : denormalizeId('serviceId'),
|
||||
|
||||
service: Ember.computed('primaryService','referencedService', function() {
|
||||
return this.get('referencedService') || this.get('primaryService');
|
||||
}),
|
||||
|
||||
stack: Ember.computed('primaryStack','referencedStack', function() {
|
||||
return this.get('referencedStack') || this.get('primaryStack');
|
||||
}),
|
||||
stack: denormalizeId('stackId'),
|
||||
|
||||
actions: {
|
||||
restart: function() {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ import Ember from 'ember';
|
|||
import Resource from 'ember-api-store/models/resource';
|
||||
import C from 'ui/utils/constants';
|
||||
import { formatSi } from 'ui/utils/util';
|
||||
import { denormalizeId } from 'ember-api-store/utils/denormalize';
|
||||
|
||||
export default Resource.extend({
|
||||
stack: denormalizeId('stackId'),
|
||||
|
||||
isSystem: function() {
|
||||
if ( this.get('system') ) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -27,10 +27,6 @@ var LoadBalancerService = Service.extend({
|
|||
let publish = this.get('launchConfig.ports')||[];
|
||||
publish.forEach((str) => {
|
||||
let spec = parsePortSpec(str,'tcp');
|
||||
if ( !spec.hostPort || spec.hostIp ) {
|
||||
this.set('hasUnsupportedPorts', true);
|
||||
}
|
||||
|
||||
if ( spec.hostPort ) {
|
||||
rules.filterBy('sourcePort', spec.hostPort).forEach((rule) => {
|
||||
rule.set('access', 'public');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Service.extend({
|
||||
intl: Ember.inject.service(),
|
||||
store: Ember.inject.service(),
|
||||
prefs: Ember.inject.service(),
|
||||
|
||||
list: function() {
|
||||
let intl = this.get('intl');
|
||||
let showSystem = this.get('prefs.showSystemResources');
|
||||
|
||||
return this.get('_allInstances').filter((inst) => !inst.get('serviceId') && (!inst.get('isSystem') || showSystem)).map((inst) => {
|
||||
let stackName = 'Standalone';
|
||||
if ( inst.get('stack') ) {
|
||||
stackName = inst.get('stack.displayName') || '('+inst.get('stackId')+')';
|
||||
}
|
||||
|
||||
return {
|
||||
group: intl.t('allServices.stackGroup', {name: stackName}),
|
||||
id: inst.get('id'),
|
||||
stackName: stackName,
|
||||
name: inst.get('displayName'),
|
||||
obj: inst,
|
||||
};
|
||||
});
|
||||
}.property('_allInstances.@each.{id,system,displayName}','prefs.showSystemResources'),
|
||||
|
||||
grouped: function() {
|
||||
return this.group(this.get('list'));
|
||||
}.property('list.[]'),
|
||||
|
||||
group(list) {
|
||||
let out = {};
|
||||
|
||||
list.slice().sortBy('group','name','id').forEach((inst) => {
|
||||
let ary = out[inst.group];
|
||||
if( !ary ) {
|
||||
ary = [];
|
||||
out[inst.group] = ary;
|
||||
}
|
||||
|
||||
ary.push(inst);
|
||||
});
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
_allInstances: function() {
|
||||
let store = this.get('store');
|
||||
store.find('instance');
|
||||
return store.all('instance');
|
||||
}.property(),
|
||||
|
||||
byId(id) {
|
||||
return this.get('store').getById('instance', id);
|
||||
},
|
||||
});
|
||||
|
|
@ -8,7 +8,12 @@ export default Ember.Service.extend({
|
|||
settings: Ember.inject.service(),
|
||||
|
||||
absolute: function() {
|
||||
var url = this.get('app.apiServer');
|
||||
let setting = this.get(`settings.${C.SETTING.API_HOST}`);
|
||||
if ( setting && setting.indexOf('http') !== 0 ) {
|
||||
setting = 'http://' + setting;
|
||||
}
|
||||
|
||||
let url = setting || this.get('app.apiServer');
|
||||
|
||||
// If the URL is relative, add on the current base URL from the browser
|
||||
if ( url.indexOf('http') !== 0 )
|
||||
|
|
@ -20,7 +25,7 @@ export default Ember.Service.extend({
|
|||
url = url.replace(/\/+$/,'') + '/';
|
||||
|
||||
return url;
|
||||
}.property('app.apiServer'),
|
||||
}.property(`settings.${C.SETTING.API_HOST}`,'app.apiServer'),
|
||||
|
||||
host: function() {
|
||||
var a = document.createElement('a');
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@
|
|||
<h1>{{t 'signupPage.header'}}</h1>
|
||||
<form class="form text-left" {{action "register" on='submit'}}>
|
||||
<div class="row">
|
||||
<label for="login-user-name">{{t 'signupPage.form.labels.loginUsername'}}</label>
|
||||
<label for="login-user-name">{{t 'signupPage.form.labels.loginUsername'}}{{field-required}}</label>
|
||||
<div name="login-user-name">
|
||||
{{input type="text" value=model.name}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row inline-form pt-15 pb-30">
|
||||
<label for="email">{{t 'signupPage.form.labels.email'}}</label>
|
||||
<label for="email">{{t 'signupPage.form.labels.email'}}{{field-required}}</label>
|
||||
<div name="email">
|
||||
{{input type="email" value=model.email}}
|
||||
</div>
|
||||
|
|
@ -38,4 +38,4 @@
|
|||
</form>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/authorize-user}}
|
||||
{{/authorize-user}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
prefs: Ember.inject.service(),
|
||||
|
||||
showAddtlInfo: false,
|
||||
selectedService: null,
|
||||
|
||||
|
|
@ -61,14 +63,6 @@ export default Ember.Controller.extend({
|
|||
},
|
||||
],
|
||||
|
||||
stackContainers: Ember.computed('model.stack.services.@each.healthState', function() {
|
||||
var neu = [];
|
||||
this.get('model.stack.services').forEach((service) => {
|
||||
neu = neu.concat(service.get('instances'));
|
||||
});
|
||||
return neu;
|
||||
}),
|
||||
|
||||
getType(ownType, real=true) {
|
||||
return this.get('model.services').filter((service) => {
|
||||
if (real ? (service.get('isReal') && service.get('kind') === ownType) : (service.get('kind') === ownType)) {
|
||||
|
|
@ -78,18 +72,28 @@ export default Ember.Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
scalingGroups: Ember.computed('model.services.@each.healthState', function() {
|
||||
scalingGroups: Ember.computed('model.services.[]', function() {
|
||||
return this.getType('scalingGroup');
|
||||
}),
|
||||
|
||||
loadBalancers: Ember.computed('model.services.@each.healthState', function() {
|
||||
loadBalancers: Ember.computed('model.services.[]', function() {
|
||||
return this.getType('loadBalancerService');
|
||||
}),
|
||||
|
||||
dnsServices: Ember.computed('model.services.@each.healthState', function() {
|
||||
dnsServices: Ember.computed('model.services.[]', function() {
|
||||
return this.getType('dnsService', false).concat(this.getType('externalService', false));
|
||||
}),
|
||||
|
||||
instances: Ember.computed('model.instances.[]','prefs.showSystemResources', function() {
|
||||
let out = this.get('model.instances').filterBy('stackId', this.get('model.stack.id'));
|
||||
out = out.filterBy('serviceId', null);
|
||||
if ( !this.get('prefs.showSystemResources') ) {
|
||||
out = out.filterBy('isSystem', false);
|
||||
}
|
||||
|
||||
return out;
|
||||
}),
|
||||
|
||||
instanceCount: function() {
|
||||
var count = 0;
|
||||
(this.get('model.stack.services')||[]).forEach((service) => {
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@
|
|||
{{#accordion-list-item
|
||||
title=(t 'stackPage.containers.header')
|
||||
detail=(t 'stackPage.containers.detail')
|
||||
status=(t 'stackPage.containers.status' count=model.instances.length)
|
||||
statusClass=(if model.instances.length 'bg-success' 'text-muted')
|
||||
status=(t 'stackPage.containers.status' count=instances.length)
|
||||
statusClass=(if instances.length 'bg-success' 'text-muted')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
componentName='container-table'
|
||||
as | parent |
|
||||
}}
|
||||
{{component parent.intent
|
||||
body=model.instances
|
||||
body=instances
|
||||
search=true
|
||||
sortBy=sortBy
|
||||
stickyHeader=false
|
||||
|
|
|
|||
|
|
@ -3,16 +3,10 @@ import Ember from 'ember';
|
|||
export default Ember.Route.extend({
|
||||
model: function(params) {
|
||||
var store = this.get('store');
|
||||
var all = this.modelFor('stacks');
|
||||
return store.find('stack', params.stack_id).then((stack) => {
|
||||
var neu = [];
|
||||
stack.get('services').forEach((service) => {
|
||||
neu = neu.concat(service.get('instances'));
|
||||
});
|
||||
return Ember.Object.create({
|
||||
stack: stack,
|
||||
all: all,
|
||||
instances: neu,
|
||||
instances: store.all('instance'),
|
||||
services: stack.get('services')
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ textarea {
|
|||
|
||||
.form-control-static {
|
||||
line-height: 24px;
|
||||
padding: 5px 0;
|
||||
padding: 3px 0;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<h2>{{t 'verifyPage.subtext'}}</h2>
|
||||
<form class="form text-left" {{action 'createAcct' on="submit"}}>
|
||||
<div class="inline-form pt-15 pb-30">
|
||||
<label for="login-user-name">{{t 'signupPage.form.labels.loginUsername'}}</label>
|
||||
<label for="login-user-name">{{t 'signupPage.form.labels.loginUsername'}}{{field-required}}</label>
|
||||
<div>
|
||||
{{input type="text" value=model.name id="login-user-name"}}
|
||||
</div>
|
||||
|
|
@ -40,4 +40,4 @@
|
|||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/authorize-user}}
|
||||
{{/authorize-user}}
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,7 @@ stackPage:
|
|||
backLink: Back to all stacks
|
||||
containers:
|
||||
header: Containers
|
||||
detail: A list of containers in this stack
|
||||
detail: Standalone Containers that are not part of a Scaling Group or Load Balancer
|
||||
status: |
|
||||
{count, plural,
|
||||
=0 {No containers}
|
||||
|
|
@ -1179,7 +1179,7 @@ stackPage:
|
|||
}
|
||||
scalingGroups:
|
||||
header: Scaling Groups
|
||||
detail: 'A list of scaling groups this stack is attached to.'
|
||||
detail: ''
|
||||
status: |
|
||||
{count, plural,
|
||||
=0 {No groups}
|
||||
|
|
@ -1188,7 +1188,7 @@ stackPage:
|
|||
}
|
||||
loadBalancers:
|
||||
header: Load Balancers
|
||||
detail: 'A list of load balancers in this stack'
|
||||
detail: ''
|
||||
status: |
|
||||
{count, plural,
|
||||
=0 {No balancers}
|
||||
|
|
@ -1196,13 +1196,13 @@ stackPage:
|
|||
other {# balancers}
|
||||
}
|
||||
dnsServices:
|
||||
header: DNS Services
|
||||
detail: 'A list of DNS Services in this stack'
|
||||
header: DNS Entries
|
||||
detail: ''
|
||||
status: |
|
||||
{count, plural,
|
||||
=0 {No rules}
|
||||
=1 {# rule}
|
||||
other {# rules}
|
||||
=0 {No entries}
|
||||
=1 {# entry}
|
||||
other {# entries}
|
||||
}
|
||||
|
||||
newStack:
|
||||
|
|
@ -1915,19 +1915,20 @@ formBalancerConfig:
|
|||
See <a href="https://cbonte.github.io/haproxy-dconv/1.6/configuration.html" target="_blank" rel="nofollow noopener">haproxy documentation</a> fore more info about specific options that can go into the the config file. When overriding the <code>backend</code> or similar lines which include the IP address of the target container, use <code>$IP</code> where the address goes and {appName} will generate the appropriate line(s).
|
||||
config:
|
||||
prompt: Custom haproxy.cfg content
|
||||
formBalancerRules:
|
||||
label: Port Rules
|
||||
detail: 'These properties show the port mapping details of your container'
|
||||
|
||||
formBalancerListeners:
|
||||
label: Listeners & Target Rules
|
||||
detail: Control the mapping of requests coming into the balancer to the desired target.
|
||||
status: |
|
||||
{count, plural,
|
||||
=0 {No rules}
|
||||
=1 {# rule}
|
||||
other {# rules}
|
||||
}
|
||||
noRules: No Rules
|
||||
addServiceLabel: Add Scaling Group Rule
|
||||
addSelectorLabel: Add Selector Rule
|
||||
target: Target
|
||||
noRules: No Ports
|
||||
addPortLabel: Add a Listening Port
|
||||
removePortLabel: Remove this Listening Port
|
||||
showBackendLabel: "Customize backend names"
|
||||
access:
|
||||
label: Access
|
||||
public: Public
|
||||
|
|
@ -1936,10 +1937,19 @@ formBalancerRules:
|
|||
label: Protocol
|
||||
sourceIp:
|
||||
label: Host IP
|
||||
placeholder: e.g. 1.2.3.4
|
||||
placeholder: "e.g. 1.2.3.4; Default: All"
|
||||
sourcePort:
|
||||
label: Port
|
||||
label: Listening Port
|
||||
placeholder: e.g. 80
|
||||
help: "Host and Path rules are matched top-to-bottom in the order shown. Backends will be named randomly by default; to customize the generated backends, provide a name and then refer to that name in your custom haproxy.cfg."
|
||||
|
||||
formBalancerRules:
|
||||
label: Target Rules
|
||||
noRules: No Rules
|
||||
addServiceLabel: Add a Service
|
||||
addInstanceLabel: Add a Container
|
||||
addSelectorLabel: Add a Selector
|
||||
addTargetLabel: Add a Rule
|
||||
path:
|
||||
label: Path
|
||||
placeholder: e.g. /foo
|
||||
|
|
@ -1956,16 +1966,14 @@ formBalancerRules:
|
|||
label: Priority
|
||||
moveUp: Move Up
|
||||
moveDown: Move Down
|
||||
serviceId:
|
||||
target: Target
|
||||
container:
|
||||
label: Container
|
||||
service:
|
||||
label: Service
|
||||
selector:
|
||||
label: Selector
|
||||
placeholder: e.g. foo=bar
|
||||
help:
|
||||
prefix: "Host and Path rules are matched top-to-bottom in the order shown. Backends will be named randomly by default; to customize the generated backends, provide a name and then refer to that in the custom haproxy.cfg. "
|
||||
showBackendLink: "Show custom backend names."
|
||||
showIpLink: "Show host IP address options."
|
||||
suffix: ""
|
||||
|
||||
formCloudHost:
|
||||
title: Host
|
||||
|
|
@ -2101,7 +2109,7 @@ formHealthCheck:
|
|||
label: Host Header
|
||||
placeholder: e.g. www.example.com
|
||||
port:
|
||||
label: Port
|
||||
label: Listening Port
|
||||
placeholder: e.g. 80
|
||||
initializingTimeout:
|
||||
label: Initializing Timeout
|
||||
|
|
@ -2431,7 +2439,7 @@ formStickiness:
|
|||
indirect: Indirect
|
||||
sendHeader: Send no-cache header
|
||||
onPost: Only set cookie on POST
|
||||
noPorts: There are no HTTP Port Rules configured.
|
||||
noPorts: There are no HTTP Listeners configured.
|
||||
|
||||
placeholder:
|
||||
sticky: e.g. sticky
|
||||
|
|
@ -3360,12 +3368,13 @@ newBalancer:
|
|||
edit: Edit Load Balancer
|
||||
upgrade: Upgrade Load Balancer
|
||||
error:
|
||||
noRules: "Choose one or more port rules to listen on"
|
||||
noRules: "You must have one or more listening ports and target rules"
|
||||
noSourcePort: "Source Port is required on each rule"
|
||||
invalidSourcePort: "Invalid source port: '{num}'"
|
||||
invalidTargetPort: "Invalid target port: '{num}'"
|
||||
mixedPort: "Port {num} has multiple rules with conflicting access/protcols"
|
||||
noTarget: "Target is required on each rule"
|
||||
noTargetPort: "Target Port is required on each rule"
|
||||
needsCertificate: "A certificate is required because there are SSL/TLS port rules"
|
||||
|
||||
newCatalog:
|
||||
|
|
@ -3614,10 +3623,12 @@ schema:
|
|||
n: "False"
|
||||
inputCertificate:
|
||||
prompt: Choose a Certificate...
|
||||
inputContainer:
|
||||
prompt: Choose a Container...
|
||||
inputEnum:
|
||||
option: Choose an option...
|
||||
inputHost:
|
||||
label: Select Host
|
||||
label: Choose a Host...
|
||||
inputService:
|
||||
prompt: Choose a Service...
|
||||
inputSecret:
|
||||
|
|
|
|||
Loading…
Reference in New Issue