Merge pull request #1198 from vincent99/master

Bugs
This commit is contained in:
Vincent Fiduccia 2017-05-29 14:36:55 -07:00 committed by GitHub
commit d1a018e93a
34 changed files with 259 additions and 182 deletions

View File

@ -14,6 +14,6 @@
expanded=(array-includes expandedStacks stack.id) expanded=(array-includes expandedStacks stack.id)
}} }}
{{else}} {{else}}
<h1>You should add a catalog item...</h1> {{empty-table resource="container" newRoute="catalog-tab" newTranslationKey="nav.apps.launch"}}
{{/each}} {{/each}}
</section> </section>

View File

@ -50,6 +50,10 @@ export default Ember.Component.extend(ManageLabels, {
} }
}, },
updateLabels(labels) {
this.sendAction('setLabels', labels);
},
// ---------------------------------- // ----------------------------------
// Capability // Capability
// ---------------------------------- // ----------------------------------
@ -81,7 +85,7 @@ export default Ember.Component.extend(ManageLabels, {
memoryMode: 'unlimited', // unlimited, set memoryMode: 'unlimited', // unlimited, set
memoryMb: null, memoryMb: null,
swapMode: 'default', // default, none, unlimited, set swapMode: 'default', // default, none, unlimited, set
swappinesMode: 'default', // default, min, set swappinessMode: 'default', // default, none, set
swapMb: null, swapMb: null,
memoryReservationMb: null, memoryReservationMb: null,
initMemory: function() { initMemory: function() {
@ -89,7 +93,6 @@ export default Ember.Component.extend(ManageLabels, {
var memPlusSwapBytes = this.get('instance.memorySwap') || 0; var memPlusSwapBytes = this.get('instance.memorySwap') || 0;
var swapBytes = Math.max(0, memPlusSwapBytes - memBytes); var swapBytes = Math.max(0, memPlusSwapBytes - memBytes);
var memReservation = this.get('instance.memoryReservation'); var memReservation = this.get('instance.memoryReservation');
var swappiness = this.get('instance.memorySwappiness');
if (memReservation) { if (memReservation) {
this.set('memoryReservationMb', parseInt(memReservation,10)/1048576); this.set('memoryReservationMb', parseInt(memReservation,10)/1048576);
@ -129,6 +132,11 @@ export default Ember.Component.extend(ManageLabels, {
} }
} }
var swappiness = this.get('instance.memorySwappiness');
if ( swappiness ) {
swappiness = parseInt(swappiness,10);
}
if ( this.get('swapMode') === 'none' || swappiness === null || swappiness === undefined ) { if ( this.get('swapMode') === 'none' || swappiness === null || swappiness === undefined ) {
this.set('instance.memorySwappiness', null); this.set('instance.memorySwappiness', null);
this.set('swappinessMode','default'); this.set('swappinessMode','default');
@ -139,28 +147,51 @@ export default Ember.Component.extend(ManageLabels, {
this.set('instance.memorySwappiness', swappiness); this.set('instance.memorySwappiness', swappiness);
this.set('swappinessMode', 'set'); this.set('swappinessMode', 'set');
} }
this.updateMemory();
}, },
memoryDidChange: function() { updateMemory: function() {
// The actual parameter we're interested in is 'memory', in bytes. // The actual parameter we're interested in is 'memory', in bytes.
let mem = parseInt(this.get('memoryMb'),10); let mem = parseInt(this.get('memoryMb'),10);
let swap = parseInt(this.get('swapMb'),10); let swap = parseInt(this.get('swapMb'),10);
let memoryMode = this.get('memoryMode'); let memoryMode = this.get('memoryMode');
let swapMode = this.get('swapMode'); let swapMode = this.get('swapMode');
let swappinessMode = this.get('swappinessMode');
let swappiness = this.get('swappiness');
// Swappiness
if ( swappinessMode === 'default' ) {
this.set('instance.memorySwappiness', null);
} else if ( swappinessMode === 'min' ) {
this.set('instance.memorySwappiness', 0);
} else {
if ( swappiness ) {
swappiness = parseInt(swappiness,10);
}
if ( isNaN(swappiness) || !swappiness ) {
swappiness = 50;
this.set('swappiness', swappiness);
return; // We'll be back
}
this.set('instance.memorySwappiness', swappiness);
}
// Memory
if ( memoryMode === 'unlimited' || isNaN(mem) || mem <= 0) { if ( memoryMode === 'unlimited' || isNaN(mem) || mem <= 0) {
this.setProperties({ this.setProperties({
'instance.memory': null, 'instance.memory': null,
'instance.memorySwap': null, 'instance.memorySwap': null,
'swapMode': 'unlimited', 'swapMode': 'unlimited',
'swappinessMode': 'set',
'instance.memorySwappiness': 0,
}); });
return; return;
} }
this.set('instance.memory', mem * 1048576); this.set('instance.memory', mem * 1048576);
// Swap
switch (swapMode) { switch (swapMode) {
case 'default': case 'default':
this.set('instance.memorySwap', null); this.set('instance.memorySwap', null);
@ -171,22 +202,23 @@ export default Ember.Component.extend(ManageLabels, {
break; break;
case 'none': case 'none':
this.set('instance.memorySwap', mem*1048576); this.set('instance.memorySwap', mem*1048576);
this.set('swappinessMode', 'min');
this.set('instance.memorySwappiness', 0);
break; break;
case 'set': case 'set':
this.set('instance.memorySwap', (mem+swap)*1048576); this.set('instance.memorySwap', (mem+swap)*1048576);
break; break;
} }
}.observes('memoryMb','memoryMode','swapMb','swapMode'), },
memoryDidChange: function() {
Ember.run.next(this,'updateMemory');
}.observes('memoryMb','memoryMode','swapMb','swapMode','swappinessMode','swappiness'),
memoryReservationChanged: Ember.observer('memoryReservationMb', function() { memoryReservationChanged: Ember.observer('memoryReservationMb', function() {
var mem = this.get('memoryReservationMb'); var mem = this.get('memoryReservationMb');
if ( isNaN(mem) || mem <= 0) { if ( isNaN(mem) || mem <= 0) {
this.set('instance.memoryReservation', null); this.set('instance.memoryReservation', null);
} } else {
else {
this.set('instance.memoryReservation', mem * 1048576); this.set('instance.memoryReservation', mem * 1048576);
} }
}), }),

View File

@ -275,6 +275,17 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
return ok; return ok;
}, },
doSave() {
if ( this.get('isService') || !this.get('isUpgrade') ) {
return this._super(...arguments);
}
// Container upgrade
return this.get('primaryResource').doAction('upgrade', {
config: this.get('primaryResource')
});
},
didSave() { didSave() {
if ( this.get('isService') ) { if ( this.get('isService') ) {
// Returns a promise // Returns a promise

View File

@ -133,7 +133,8 @@ export default Ember.Component.extend(NewOrEdit, {
}.observes( }.observes(
'userLabels.@each.{key,value}', 'userLabels.@each.{key,value}',
'scaleLabels.@each.{key,value}', 'scaleLabels.@each.{key,value}',
'schedulingLabels.@each.{key,value}' 'schedulingLabels.@each.{key,value}',
'stickinessLabels.@each.{key,value}'
), ),
mergeLabels() { mergeLabels() {
@ -145,6 +146,7 @@ export default Ember.Component.extend(NewOrEdit, {
(this.get('userLabels')||[]).forEach((row) => { out[row.key] = row.value; }); (this.get('userLabels')||[]).forEach((row) => { out[row.key] = row.value; });
(this.get('scaleLabels')||[]).forEach((row) => { out[row.key] = row.value; }); (this.get('scaleLabels')||[]).forEach((row) => { out[row.key] = row.value; });
(this.get('schedulingLabels')||[]).forEach((row) => { out[row.key] = row.value; }); (this.get('schedulingLabels')||[]).forEach((row) => { out[row.key] = row.value; });
(this.get('stickinessLabels')||[]).forEach((row) => { out[row.key] = row.value; });
var config = this.get('launchConfig'); var config = this.get('launchConfig');
if ( config ) if ( config )

View File

@ -52,12 +52,10 @@
setLabels=(action 'setLabels' 'scheduling') setLabels=(action 'setLabels' 'scheduling')
}} }}
{{#liquid-if service.lbConfig.needsCertificate}} {{form-ssl-termination
{{form-ssl-termination service=service
service=service allCertificates=allCertificates
allCertificates=allCertificates }}
}}
{{/liquid-if}}
{{#advanced-section advanced=false}} {{#advanced-section advanced=false}}
{{#accordion-list as | al expandFn | }} {{#accordion-list as | al expandFn | }}
@ -75,6 +73,8 @@
}} }}
{{form-stickiness {{form-stickiness
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'stickiness')
service=service service=service
expandAll=al.expandAll expandAll=al.expandAll
expandFn=expandFn expandFn=expandFn

View File

@ -70,7 +70,7 @@ export default Ember.Component.extend({
validate() { validate() {
var errors = []; var errors = [];
var globals = ['all', 'community', 'library']; // these should be removed when these terms are removed from the envid field var global = this.get('global');
var ary = this.get('ary'); var ary = this.get('ary');
ary.forEach((cat) => { ary.forEach((cat) => {
@ -82,7 +82,8 @@ export default Ember.Component.extend({
errors.push('URL is required on each catalog'); errors.push('URL is required on each catalog');
} }
if (globals.indexOf(cat.name.toLowerCase()) >= 0 || ary.filter((x) => (x.name||'').trim().toLowerCase() === cat.name.toLowerCase()).length > 1) { if ( global.filter((x) => (x.name||'').trim().toLowerCase() === cat.name.toLowerCase()).length > 1 ||
ary.filter((x) => (x.name||'').trim().toLowerCase() === cat.name.toLowerCase()).length > 1) {
errors.push('Each catalog must have a unique name'); errors.push('Each catalog must have a unique name');
} }
}); });

View File

@ -8,7 +8,6 @@ export default Ember.Component.extend({
ports: null, ports: null,
protocolChoices: null, protocolChoices: null,
showBackend: null,
errors: null, errors: null,
onInit: function() { onInit: function() {
@ -67,11 +66,6 @@ export default Ember.Component.extend({
protos.removeObject('udp'); protos.removeObject('udp');
protos.sort(); protos.sort();
this.set('protocolChoices', protos); this.set('protocolChoices', protos);
if ( this.get('showBackend') === null ) {
let hasName = !!rules.findBy('backendName');
this.set('showBackend', hasName);
}
}.on('init'), }.on('init'),
shouldFlattenAndValidate: function() { shouldFlattenAndValidate: function() {
@ -196,10 +190,6 @@ export default Ember.Component.extend({
this.get('ports').removeObject(port); this.get('ports').removeObject(port);
}, },
showBackend() {
this.set('showBackend', true);
},
rulesChanged() { rulesChanged() {
this.shouldFlattenAndValidate(); this.shouldFlattenAndValidate();
}, },

View File

@ -6,13 +6,6 @@
<span class="darken"><i class="icon icon-plus text-small"></i></span> <span class="darken"><i class="icon icon-plus text-small"></i></span>
<span>{{t 'formBalancerListeners.addPortLabel'}}</span> <span>{{t 'formBalancerListeners.addPortLabel'}}</span>
</button> </button>
{{#unless showBackend}}
<div class="pull-right clearfix">
<button class="btn bg-transparent text-small inline-block" {{action "showBackend"}}>
{{t 'formBalancerListeners.showBackendLabel'}}
</button>
</div>
{{/unless}}
</div> </div>
</div> </div>
<hr/> <hr/>
@ -63,7 +56,6 @@
protocol=port.protocol protocol=port.protocol
rulesChanged=(action 'rulesChanged') rulesChanged=(action 'rulesChanged')
singleTarget=false singleTarget=false
showBackend=showBackend
editing=true editing=true
}} }}
<div class="clearfix"> <div class="clearfix">

View File

@ -5,9 +5,18 @@ export default Ember.Component.extend({
singleTarget: true, singleTarget: true,
protocol: null, protocol: null,
editing: true, editing: true,
showBackend: null,
ruleType: 'portRule', ruleType: 'portRule',
didReceiveAttrs() {
this._super(...arguments);
if ( this.get('showBackend') !== true ) {
let hasName = !!((this.get('rules')||[]).findBy('backendName'));
this.set('showBackend', hasName);
}
},
rulesChanged: function() { rulesChanged: function() {
this.sendAction('rulesChanged'); this.sendAction('rulesChanged');
}.observes('rules.@each.{hostname,path,kind,instanceId,serviceId,selector,targetPort,backendName}'), }.observes('rules.@each.{hostname,path,kind,instanceId,serviceId,selector,targetPort,backendName}'),
@ -55,6 +64,10 @@ export default Ember.Component.extend({
removeRule(rule) { removeRule(rule) {
this.get('rules').removeObject(rule); this.get('rules').removeObject(rule);
}, },
showBackend() {
this.set('showBackend', true);
},
}, },
protocolChanged: function() { protocolChanged: function() {

View File

@ -116,6 +116,13 @@
{{/each}} {{/each}}
</tbody> </tbody>
</table> </table>
{{#unless showBackend}}
<div class="pull-right clearfix">
<button class="btn bg-transparent p-0 pl-20 text-small inline-block" {{action "showBackend"}}>
{{t 'formBalancerListeners.showBackendLabel'}}
</button>
</div>
{{/unless}}
{{else}} {{else}}
<span class="text-muted">{{t 'formBalancerRules.noRules'}}</span> <span class="text-muted">{{t 'formBalancerRules.noRules'}}</span>
{{/if}} {{/if}}

View File

@ -47,7 +47,6 @@ export default Ember.Component.extend({
showUriHost: Ember.computed.equal('uriVersion', HTTP_1_1), showUriHost: Ember.computed.equal('uriVersion', HTTP_1_1),
strategy: null, strategy: null,
quorum: null,
actions: { actions: {
chooseUriMethod(method) { chooseUriMethod(method) {
@ -96,7 +95,6 @@ export default Ember.Component.extend({
this.setProperties({ this.setProperties({
strategy: this.get('healthCheck.strategy') || 'recreate', strategy: this.get('healthCheck.strategy') || 'recreate',
quorum: this.get('healthCheck.recreateOnQuorumStrategyConfig.quorum') || '1',
}); });
} }
else else
@ -108,7 +106,6 @@ export default Ember.Component.extend({
uriVersion: HTTP_1_0, uriVersion: HTTP_1_0,
uriHost: '', uriHost: '',
strategy: 'recreate', strategy: 'recreate',
quorum: '1',
}); });
} }
@ -164,27 +161,8 @@ export default Ember.Component.extend({
var strategy = this.get('strategy'); var strategy = this.get('strategy');
var hc = this.get('healthCheck'); var hc = this.get('healthCheck');
if ( strategy === 'recreateOnQuorum' ) hc.set('strategy', strategy);
{ }.observes('strategy'),
hc.setProperties({
'strategy': strategy,
'recreateOnQuorumStrategyConfig': {
quorum: parseInt(this.get('quorum'),10),
},
});
}
else
{
hc.setProperties({
'strategy': strategy,
'recreateOnQuorumStrategyConfig': null,
});
}
}.observes('strategy','quorum'),
quorumDidChange: function() {
this.set('strategy', 'recreateOnQuorum');
}.observes('quorum'),
validate: function() { validate: function() {
var errors = []; var errors = [];

View File

@ -159,16 +159,6 @@
<div class="radio"> <div class="radio">
<label>{{radio-button selection=strategy value="recreate"}} {{t 'formHealthCheck.strategy.recreate'}}</label> <label>{{radio-button selection=strategy value="recreate"}} {{t 'formHealthCheck.strategy.recreate'}}</label>
</div> </div>
<div class="radio">
<label>
{{radio-button selection=strategy value="recreateOnQuorum"}}
<span class="with-input">
{{t 'formHealthCheck.strategy.recreateOnQuorumPrefix' quorum=quorum}}
{{input-integer min=1 safeStyle="width: 60px; display: inline-block;" class="form-control input-xs" value=quorum}}
{{t 'formHealthCheck.strategy.recreateOnQuorumSuffix' quorum=quorum}}
</span>
</label>
</div>
{{/input-or-display}} {{/input-or-display}}
{{/if}} {{/if}}
{{/if}} {{/if}}

View File

@ -7,76 +7,79 @@
expand=(action expandFn) expand=(action expandFn)
}} }}
{{#if allCertificates.length}} {{#liquid-if service.lbConfig.needsCertificate}}
<div class="row inline-form"> {{#if allCertificates.length}}
<div class="col span-2 col-inline"> <div class="row inline-form">
<label>{{t 'formSslTermination.certificate'}}</label> <div class="col span-2 col-inline">
<label>{{t 'formSslTermination.certificate'}}{{field-required}}</label>
</div>
<div class="col span-8">
{{new-select
classNames="form-control"
prompt=(t 'formSslTermination.defaultCertificate.prompt')
content=allCertificates
optionLabelPath="displayDetailedName"
optionValuePath="id"
value=lbConfig.defaultCertificateId
}}
</div>
</div> </div>
<div class="col span-8">
{{new-select
classNames="form-control"
prompt=(t 'formSslTermination.defaultCertificate.prompt')
content=allCertificates
optionLabelPath="displayDetailedName"
optionValuePath="id"
value=lbConfig.defaultCertificateId
}}
</div>
</div>
<div class="row inline-form"> <div class="row inline-form">
<div class="col span-2 col-inline"> <div class="col span-2 col-inline">
<label>{{t 'formSslTermination.alternateCerts'}}</label> <label>{{t 'formSslTermination.alternateCerts'}}</label>
</div> </div>
<div class="col span-8"> <div class="col span-8">
<table class="table fixed no-lines no-top-padding"> <table class="table fixed no-lines no-top-padding">
<thead> <thead>
<tr>
<td>
{{#if alternateCertificates.length}}
<button class="btn bg-link icon-btn" {{action "addAlternate"}}>
<span class="darken"><i class="icon icon-plus text-small"/></span>
<span>{{t 'formSslTermination.addAlternate'}}</span>
</button>
{{else}}
<span class="text-muted">{{t 'formSslTermination.noAlternateCertificates'}}</span>
{{/if}}
</td>
<th width="30">&nbsp;</th>
</tr>
</thead>
<tbody>
{{#each alternates as |alt|}}
<tr> <tr>
<td> <td>
{{new-select {{#if alternateCertificates.length}}
classNames="form-control" <button class="btn bg-link icon-btn" {{action "addAlternate"}}>
prompt=(t 'formSslTermination.alternateCertificate.prompt') <span class="darken"><i class="icon icon-plus text-small"/></span>
content=alternateCertificates <span>{{t 'formSslTermination.addAlternate'}}</span>
optionLabelPath="displayDetailedName" </button>
optionValuePath="id" {{else}}
value=alt.value <span class="text-muted">{{t 'formSslTermination.noAlternateCertificates'}}</span>
}} {{/if}}
</td>
<td class="text-right">
{{#unless link.existing}}
<button class="btn bg-primary btn-sm" {{action "removeAlternate" alt}}><i class="icon icon-minus"/></button>
{{/unless}}
</td> </td>
<th width="30">&nbsp;</th>
</tr> </tr>
{{/each}} </thead>
</tbody> <tbody>
</table> {{#each alternates as |alt|}}
<tr>
<td>
{{new-select
classNames="form-control"
prompt=(t 'formSslTermination.alternateCertificate.prompt')
content=alternateCertificates
optionLabelPath="displayDetailedName"
optionValuePath="id"
value=alt.value
}}
</td>
<td class="text-right">
{{#unless link.existing}}
<button class="btn bg-primary btn-sm" {{action "removeAlternate" alt}}><i class="icon icon-minus"/></button>
{{/unless}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div> </div>
</div>
<div class="row inline-form"> <div class="row inline-form">
<div class="offset-2 col offset-8"> <div class="offset-2 col offset-8">
<p class="text-info">{{t 'formSslTermination.helpBlock' htmlSafe=true}}</p> <p class="text-info">{{t 'formSslTermination.helpBlock' htmlSafe=true}}</p>
</div>
</div> </div>
</div> {{else}}
<span class="text-muted">{{t 'formSslTermination.noCertificates'}}</span>
{{/if}}
{{else}} {{else}}
<span class="text-muted">{{t 'formSslTermination.noCertificates'}}</span> <span class="text-muted">{{t 'formSslTermination.notNeeded'}}</span>
{{/if}} {{/liquid-if}}
{{/accordion-list-item}} {{/accordion-list-item}}

View File

@ -1,7 +1,9 @@
import Ember from 'ember'; import Ember from 'ember';
import { STATUS, STATUS_INTL_KEY, classForStatus } from 'ui/components/accordion-list-item/component'; import { STATUS, STATUS_INTL_KEY, classForStatus } from 'ui/components/accordion-list-item/component';
import C from 'ui/utils/constants';
import ManageLabels from 'ui/mixins/manage-labels';
export default Ember.Component.extend({ export default Ember.Component.extend(ManageLabels, {
service : null, service : null,
intl: Ember.inject.service(), intl: Ember.inject.service(),
@ -38,12 +40,20 @@ export default Ember.Component.extend({
}); });
} }
this.initLabels(this.get('initialLabels'), null, C.LABEL.BALANCER_TARGET);
var target = this.getLabel(C.LABEL.BALANCER_TARGET)||'any';
this.setProperties({ this.setProperties({
policy: policy, policy: policy,
stickiness: stickiness, stickiness: stickiness,
balancerTarget: target,
}); });
}, },
updateLabels(labels) {
this.sendAction('setLabels', labels);
},
stickinessDidChange: function() { stickinessDidChange: function() {
var stickiness = this.get('stickiness'); var stickiness = this.get('stickiness');
if ( !this.get('lbConfig.canSticky') || stickiness === 'none' ) if ( !this.get('lbConfig.canSticky') || stickiness === 'none' )
@ -56,6 +66,15 @@ export default Ember.Component.extend({
} }
}.observes('stickiness','lbConfig.canSticky'), }.observes('stickiness','lbConfig.canSticky'),
balancerTargetDidChange: function() {
let target = this.get('balancerTarget');
if ( target === 'any' ) {
this.removeLabel(C.LABEL.BALANCER_TARGET, true);
} else {
this.setLabel(C.LABEL.BALANCER_TARGET, target);
}
}.observes('balancerTarget'),
statusClass: null, statusClass: null,
status: function() { status: function() {
let k = STATUS.NOTCONFIGURED; let k = STATUS.NOTCONFIGURED;

View File

@ -6,6 +6,21 @@
expandAll=expandAll expandAll=expandAll
expand=(action expandFn) expand=(action expandFn)
}} }}
<label>{{t 'formStickiness.balancerTarget'}}</label>
<div class="radio">
<label>{{radio-button selection=balancerTarget value="any"}} {{t 'formStickiness.any' htmlSafe=true}}</label>
</div>
<div class="radio">
<label>{{radio-button selection=balancerTarget value="prefer-local"}} {{t 'formStickiness.preferLocal' htmlSafe=true}}</label>
</div>
<div class="radio">
<label>{{radio-button selection=balancerTarget value="only-local"}} {{t 'formStickiness.onlyLocal' htmlSafe=true}}</label>
</div>
<hr/>
<label>{{t 'formStickiness.sticky'}}</label>
{{#liquid-if lbConfig.canSticky}} {{#liquid-if lbConfig.canSticky}}
<div class="row {{unless isNone 'inline-form'}}"> <div class="row {{unless isNone 'inline-form'}}">
<div class="col span-2 radio"> <div class="col span-2 radio">
@ -62,5 +77,7 @@
</div> </div>
</div> </div>
{{/liquid-if}} {{/liquid-if}}
{{else}}
<span class="text-muted">{{t 'formStickiness.noPorts'}}</span>
{{/liquid-if}} {{/liquid-if}}
{{/accordion-list-item}} {{/accordion-list-item}}

View File

@ -78,7 +78,7 @@
{{/each}} {{/each}}
{{else}} {{else}}
{{#each groupedInstances as |group|}} {{#each groupedInstances as |group|}}
{{#if (or showAdd group.instances.length)}} {{#if group.instances.length}}
<div class="container-subpod-info"> <div class="container-subpod-info">
<div class="subpod-header"> <div class="subpod-header">
<h6 class="clip"> <h6 class="clip">
@ -99,19 +99,13 @@
{{#each group.instances as |item|}} {{#each group.instances as |item|}}
{{container-subpod model=item.main children=item.children}} {{container-subpod model=item.main children=item.children}}
{{/each}} {{/each}}
{{#unless group.name}}
{{#if showAdd}}
{{add-subpod action="newContainer" label="hostsPage.addContainer" groupHasChildren=group.hasChildren}}
{{/if}}
{{/unless}}
</div> </div>
</div> </div>
{{/if}} {{/if}}
{{else}}
{{#if showAdd}}
{{add-subpod action="newContainer" label="hostsPage.addContainer" groupHasChildren=group.hasChildren}}
{{/if}}
{{/each}} {{/each}}
{{#if showAdd}}
{{add-subpod action="newContainer" label="hostsPage.addContainer" groupHasChildren=group.hasChildren}}
{{/if}}
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}

View File

@ -167,9 +167,8 @@ export default Ember.Component.extend(NewOrEdit, {
item.answer = item.default; item.answer = item.default;
} }
}); });
return response;
} }
return response;
}); });
this.set('selectedTemplateModel', selectedTemplateModel); this.set('selectedTemplateModel', selectedTemplateModel);

View File

@ -39,7 +39,7 @@ export default Ember.Component.extend({
let map = {}; let map = {};
// Start with ours, then load the users in case they override the value // Start with ours, then load the users in case they override the value
if (this.get('enableLibrary')) { if (this.get('enableLibrary')) {
map[C.CATALOG.LIBRARY_KEY] = {url: C.CATALOG.LIBRARY_VALUE, branch: def}; map[C.CATALOG.LIBRARY_KEY] = {url: C.CATALOG.LIBRARY_VALUE, branch: C.CATALOG.LIBRARY_BRANCH};
} }
if (this.get('enableCommunity')) { if (this.get('enableCommunity')) {
@ -79,7 +79,7 @@ export default Ember.Component.extend({
let library = false; let library = false;
let entry = map[C.CATALOG.LIBRARY_KEY]; let entry = map[C.CATALOG.LIBRARY_KEY];
if ( entry && entry.url === C.CATALOG.LIBRARY_VALUE && entry.branch === def ) { if ( entry && entry.url === C.CATALOG.LIBRARY_VALUE && entry.branch === C.CATALOG.LIBRARY_BRANCH ) {
library = true; library = true;
delete map[C.CATALOG.LIBRARY_KEY]; delete map[C.CATALOG.LIBRARY_KEY];
} }

View File

@ -6,6 +6,7 @@ const ALLOWED = {
'access.log': {description: 'Path to write access logs to (HA installation only)'}, 'access.log': {description: 'Path to write access logs to (HA installation only)'},
'api.auth.jwt.token.expiry': {description: 'Authorization token/UI session lifetime (milliseconds)', kind: 'int'}, 'api.auth.jwt.token.expiry': {description: 'Authorization token/UI session lifetime (milliseconds)', kind: 'int'},
'api.auth.realm': {description: 'HTTP Basic Auth realm for requests without Authorization header'}, 'api.auth.realm': {description: 'HTTP Basic Auth realm for requests without Authorization header'},
'api.auth.restrict.concurrent.sessions': {description: 'Limit active session tokens to one per account. This mainly prevents users from logging in to the UI from multiple computers simultaneously. Note: Existing sessions may continue to be valid until they expire when this is initially enabled.', kind: 'boolean'},
'api.interceptor.config': {description: 'JSON configuration for API Interceptor', kind: 'multiline'}, 'api.interceptor.config': {description: 'JSON configuration for API Interceptor', kind: 'multiline'},
'api.proxy.allow': {description: 'Allow use of /v1/proxy to talk to whitelisted domains, for custom Add Host UIs', kind: 'boolean'}, 'api.proxy.allow': {description: 'Allow use of /v1/proxy to talk to whitelisted domains, for custom Add Host UIs', kind: 'boolean'},
'api.proxy.whitelist': {description: 'Whitelist of domains to that can be proxied through /v1/proxy to, for custom Add Host UIs'}, 'api.proxy.whitelist': {description: 'Whitelist of domains to that can be proxied through /v1/proxy to, for custom Add Host UIs'},
@ -38,7 +39,7 @@ const ALLOWED = {
'ui.sendgrid.template.password_reset': {description: 'SendGrid template for initiating password reset', mode: C.MODE.CAAS}, 'ui.sendgrid.template.password_reset': {description: 'SendGrid template for initiating password reset', mode: C.MODE.CAAS},
'ui.sendgrid.template.create_user': {description: 'SendGrid template for confirming email', mode: C.MODE.CAAS}, 'ui.sendgrid.template.create_user': {description: 'SendGrid template for confirming email', mode: C.MODE.CAAS},
'ui.sendgrid.template.verify_password': {description: 'SendGrid template for confirming password reset', mode: C.MODE.CAAS}, 'ui.sendgrid.template.verify_password': {description: 'SendGrid template for confirming password reset', mode: C.MODE.CAAS},
'upgrade.manager': {description: 'Automatic upgrades of infrastructure stacks', kind: 'boolean'}, 'upgrade.manager': {description: 'Automatic upgrades of infrastructure stacks', kind: 'enum', options: ['all','mandatory','none']},
}; };
export default Ember.Component.extend({ export default Ember.Component.extend({

View File

@ -16,7 +16,7 @@ export default Ember.Route.extend({
if ( params.upgrade ) if ( params.upgrade )
{ {
return Ember.Object.create({ return Ember.Object.create({
instance: instance, instance: results.existing.clone(),
}); });
} }

View File

@ -1,5 +1,5 @@
{{container/new-edit {{container/new-edit
isUpgrade=isUpgrade isUpgrade=upgrade
isService=false isService=false
launchConfig=model.instance launchConfig=model.instance
primaryResource=model.instance primaryResource=model.instance

View File

@ -20,7 +20,7 @@ const defaultStateMap = {
'initializing': {icon: 'icon icon-alert', color: 'text-warning'}, 'initializing': {icon: 'icon icon-alert', color: 'text-warning'},
'migrating': {icon: 'icon icon-info', color: 'text-info' }, 'migrating': {icon: 'icon icon-info', color: 'text-info' },
'provisioning': {icon: 'icon icon-circle', color: 'text-info' }, 'provisioning': {icon: 'icon icon-circle', color: 'text-info' },
'garbage-collection': {icon: 'icon icon-trash', color: 'text-success'}, 'pending-delete': {icon: 'icon icon-trash', color: 'text-muted' },
'purged': {icon: 'icon icon-purged', color: 'text-error' }, 'purged': {icon: 'icon icon-purged', color: 'text-error' },
'purging': {icon: 'icon icon-purged', color: 'text-info' }, 'purging': {icon: 'icon icon-purged', color: 'text-info' },
'reconnecting': {icon: 'icon icon-alert', color: 'text-error' }, 'reconnecting': {icon: 'icon icon-alert', color: 'text-error' },

View File

@ -87,6 +87,11 @@ export default Ember.Mixin.create({
} }
remaining.removeObjects(related); remaining.removeObjects(related);
} else if ( stackId ) {
let unit = getOrCreateUnit(groupId, groupName, instance.get('id'));
unit.group.hasChildren = false;
unit.main = instance;
remaining.removeObject(instance);
} else { } else {
orphans = [instance]; orphans = [instance];
} }

View File

@ -16,6 +16,10 @@ export default Ember.Mixin.create({
this.get(inputKey).sortBy('stateSort').forEach((inst) => { this.get(inputKey).sortBy('stateSort').forEach((inst) => {
let color = inst.get('stateBackground'); let color = inst.get('stateBackground');
if ( color === 'bg-muted' ) {
color = 'bg-success';
}
let state = inst.get('displayState'); let state = inst.get('displayState');
let entry = byName.findBy('state', state); let entry = byName.findBy('state', state);
if ( entry ) { if ( entry ) {
@ -42,7 +46,7 @@ export default Ember.Mixin.create({
this.set(sortProperty, Ember.computed(countsProperty, `${inputKey}.[]`, () => { this.set(sortProperty, Ember.computed(countsProperty, `${inputKey}.[]`, () => {
let colors = this.get(`${countsProperty}.byColor`); let colors = this.get(`${countsProperty}.byColor`);
let success = (colors.findBy('bg-success')||{}).count; let success = (colors.findBy('bg-success')||{}).count + (colors.findBy('bg-muted')||{}).coun;
let error = (colors.findBy('bg-error')||{}).count; let error = (colors.findBy('bg-error')||{}).count;
let other = this.get(`${inputKey}.length`) - success - error; let other = this.get(`${inputKey}.length`) - success - error;

View File

@ -143,8 +143,8 @@ var Container = Instance.extend({
var health = this.get('healthState'); var health = this.get('healthState');
var hasCheck = !!this.get('healthCheck'); var hasCheck = !!this.get('healthCheck');
if ( this.get('desired') === false ) { if ( resource === 'stopped' && this.get('desired') === false ) {
return 'garbage-collection'; return 'pending-delete';
} }
else if ( C.ACTIVEISH_STATES.indexOf(resource) >= 0 ) else if ( C.ACTIVEISH_STATES.indexOf(resource) >= 0 )
{ {

View File

@ -72,7 +72,7 @@ var Host = Resource.extend(StateCounts,{
var out = [ var out = [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!a.update }, { label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!a.update },
{ label: 'action.clone', icon: 'icon icon-copy', action: 'clone', enabled: !!this.get('driver') } // { label: 'action.clone', icon: 'icon icon-copy', action: 'clone', enabled: !!this.get('driver') }
]; ];
if ( this.get('links.config') ) if ( this.get('links.config') )

View File

@ -41,6 +41,7 @@ var Identity = Resource.extend({
case C.PROJECT.TYPE_GITHUB_USER: case C.PROJECT.TYPE_GITHUB_USER:
case C.PROJECT.TYPE_LDAP_USER: case C.PROJECT.TYPE_LDAP_USER:
case C.PROJECT.TYPE_OPENLDAP_USER: case C.PROJECT.TYPE_OPENLDAP_USER:
case C.PROJECT.TYPE_SHIBBOLETH_USER:
return C.PROJECT.PERSON; return C.PROJECT.PERSON;
case C.PROJECT.TYPE_GITHUB_TEAM: case C.PROJECT.TYPE_GITHUB_TEAM:
@ -50,6 +51,7 @@ var Identity = Resource.extend({
case C.PROJECT.TYPE_AZURE_GROUP: case C.PROJECT.TYPE_AZURE_GROUP:
case C.PROJECT.TYPE_LDAP_GROUP: case C.PROJECT.TYPE_LDAP_GROUP:
case C.PROJECT.TYPE_OPENLDAP_GROUP: case C.PROJECT.TYPE_OPENLDAP_GROUP:
case C.PROJECT.TYPE_SHIBBOLETH_GROUP:
return C.PROJECT.ORG; return C.PROJECT.ORG;
} }
}.property('externalIdType'), }.property('externalIdType'),
@ -73,11 +75,13 @@ var Identity = Resource.extend({
case C.PROJECT.TYPE_AZURE_USER: case C.PROJECT.TYPE_AZURE_USER:
case C.PROJECT.TYPE_LDAP_USER: case C.PROJECT.TYPE_LDAP_USER:
case C.PROJECT.TYPE_OPENLDAP_USER: case C.PROJECT.TYPE_OPENLDAP_USER:
case C.PROJECT.TYPE_SHIBBOLETH_USER:
key = 'model.identity.displayType.user'; key = 'model.identity.displayType.user';
break; break;
case C.PROJECT.TYPE_AZURE_GROUP: case C.PROJECT.TYPE_AZURE_GROUP:
case C.PROJECT.TYPE_LDAP_GROUP: case C.PROJECT.TYPE_LDAP_GROUP:
case C.PROJECT.TYPE_OPENLDAP_GROUP: case C.PROJECT.TYPE_OPENLDAP_GROUP:
case C.PROJECT.TYPE_SHIBBOLETH_GROUP:
key = 'model.identity.displayType.group'; key = 'model.identity.displayType.group';
break; break;
case C.PROJECT.TYPE_GITHUB_TEAM: case C.PROJECT.TYPE_GITHUB_TEAM:

View File

@ -94,6 +94,7 @@ var Service = Resource.extend(StateCounts, {
switch ( this.get('lcType') ) switch ( this.get('lcType') )
{ {
case 'service': route = 'scaling-groups.new'; break; case 'service': route = 'scaling-groups.new'; break;
case 'scalinggroup': route = 'scaling-groups.new'; break;
case 'dnsservice': route = 'dns.new'; break; case 'dnsservice': route = 'dns.new'; break;
case 'loadbalancerservice': route = 'balancers.new'; break; case 'loadbalancerservice': route = 'balancers.new'; break;
case 'externalservice': route = 'dns.new'; break; case 'externalservice': route = 'dns.new'; break;

View File

@ -21,6 +21,7 @@
<hr class="mt-40 mb-40"/> <hr class="mt-40 mb-40"/>
<div class="pb-10"> <div class="pb-10">
{{input-files {{input-files
accept=".yml, .yaml"
changed=(action (mut files)) changed=(action (mut files))
header='newStack.files.label' header='newStack.files.label'
addActionLabel='newStack.files.addActionLabel' addActionLabel='newStack.files.addActionLabel'

View File

@ -105,9 +105,10 @@ export default Ember.Service.extend({
case 'never': case 'never':
return false; return false;
case 'default_hide': case 'default_hide':
return user !== true; return user === true;
default: default:
// also 'default_show': // also 'default_show':
// user can be null so it must be exactly false
return user !== false; return user !== false;
} }
}, },

View File

@ -11,6 +11,16 @@
&.text-success:hover { &.text-success:hover {
color: $success; color: $success;
} }
// Successful states are de-emphasized by using [text-]color instead of background-color
&.bg-muted {
background-color: transparent;
color: $text-muted;
}
&.text-success:hover {
color: $text-muted;
}
} }
.grid TD.state { .grid TD.state {

View File

@ -29,6 +29,7 @@ var C = {
COMMUNITY_KEY: 'community', COMMUNITY_KEY: 'community',
COMMUNITY_VALUE: 'https://git.rancher.io/community-catalog.git', COMMUNITY_VALUE: 'https://git.rancher.io/community-catalog.git',
DEFAULT_BRANCH: 'master', DEFAULT_BRANCH: 'master',
LIBRARY_BRANCH: '${RELEASE}',
}, },
COOKIE: { COOKIE: {
@ -174,6 +175,7 @@ var C = {
LAUNCH_CONFIG: 'io.rancher.service.launch.config', LAUNCH_CONFIG: 'io.rancher.service.launch.config',
LAUNCH_CONFIG_PRIMARY: 'io.rancher.service.primary.launch.config', LAUNCH_CONFIG_PRIMARY: 'io.rancher.service.primary.launch.config',
SIDEKICK: 'io.rancher.sidekicks', SIDEKICK: 'io.rancher.sidekicks',
BALANCER_TARGET: 'io.rancher.lb_service.target'
}, },
LANGUAGE: { LANGUAGE: {

View File

@ -491,7 +491,7 @@ containerPage:
security: Security security: Security
portsTab: portsTab:
header: Ports header: Ports
detail: 'These properties show what ports have been mapped and where.' detail: 'Mappings of container listening ports to host ports on public IP addresses'
status: | status: |
{count, plural, {count, plural,
=0 {No Ports} =0 {No Ports}
@ -1080,7 +1080,7 @@ servicePage:
noData: No Links noData: No Links
certsTab: certsTab:
title: Certificates title: Certificates
detail: 'Certificates added to service.' detail: 'Certificates used for TLS-termination of requests.'
status: | status: |
{count, plural, {count, plural,
=0 {No certificates} =0 {No certificates}
@ -1104,7 +1104,7 @@ servicePage:
placeholder: e.g. Balancer for mycompany.com placeholder: e.g. Balancer for mycompany.com
portsTab: portsTab:
title: Ports title: Ports
detail: 'These properties show what ports have been mapped and where.' detail: 'Mappings of container listening ports to host ports on public IP addresses.'
status: | status: |
{count, plural, {count, plural,
=0 {No Ports} =0 {No Ports}
@ -1154,10 +1154,10 @@ signupPage:
form: form:
button: Register button: Register
labels: labels:
loginUsername: Name* loginUsername: Name
email: Email* email: Email
cc: Credit Card Info cc: Credit Card Info
pw: Password* pw: Password
emailSuccess: emailSuccess:
header: Welcome to Container Cloud header: Welcome to Container Cloud
confirm: confirm:
@ -1982,7 +1982,7 @@ formCloudHost:
formCommand: formCommand:
title: Command title: Command
detail: These properties control the executable that will be run when the container is started. detail: Configuration of the executable that will be run when the container is started.
command: command:
label: Command label: Command
placeholder: e.g. /usr/sbin/httpd -f httpd.conf placeholder: e.g. /usr/sbin/httpd -f httpd.conf
@ -2092,8 +2092,8 @@ formEngineOpts:
formHealthCheck: formHealthCheck:
title: Health Check title: Health Check
detail: A health check allows {appName} to know if your container is healthy. For scaling groups, an unhealthy container can be automatically replaced. detail: Periodically make a request to the container to see if it is responding correctly. An unhealthy container will be excluded from Load Balancers. Scaling Groups can automatically replace unhealthy containers with a new one.
detailDns: A health check allows {appName} to know if the external resource is healty or not. This will be used when this record is the target of a Load Balancer. detailDns: A health check allows {appName} to know if the external resource is healty or not. An unhealthy target will be exlcluded from Load Balancers.
checkType: checkType:
none: None none: None
tcp: Check that a TCP connection opens successfully tcp: Check that a TCP connection opens successfully
@ -2134,12 +2134,6 @@ formHealthCheck:
label: When Unhealthy label: When Unhealthy
none: Take no action none: Take no action
recreate: Re-create recreate: Re-create
recreateOnQuorumPrefix: Re-create, but only if at least
recreateOnQuorumSuffix: |
{quorum, plural,
=1 {container is}
other {containers are}
} healthy
formKeyValue: formKeyValue:
addAction: Add Pair addAction: Add Pair
@ -2402,14 +2396,14 @@ formSslTermination:
prompt: Choose a Certificate... prompt: Choose a Certificate...
alternateCertificate: alternateCertificate:
prompt: Choose a Certificate... prompt: Choose a Certificate...
certificate: Certificate* certificate: Certificate
alternateCerts: Alternate Certs alternateCerts: Alternate Certs
addAlternate: Add Alternate Certificate addAlternate: Add Alternate Certificate
noCertificates: There are no certificates to use. noCertificates: There are no certificates to use.
noAlternateCertificates: There are no other certificates to use. noAlternateCertificates: There are no other certificates to use.
helpBlock: | helpBlock: |
"Note: Some older SSL/TLS clients do not support <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" target="_blank">Server Name Indication (SNI)</a>; these clients will always be offered the main Certificate Modern clients will be offered an appropriate certificate from the Alternate Certificates list if a match is found." "Note: Some older SSL/TLS clients do not support <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" target="_blank">Server Name Indication (SNI)</a>; these clients will always be offered the main Certificate. Modern clients will be offered an appropriate certificate from the Alternate Certificates list if a match is found."
notNeeded: There are no SSL/TLS ports configured. notNeeded: There are no SSL/TLS Listening Ports configured with a valid Target Rule.
formStack: formStack:
label: label:
@ -2429,10 +2423,16 @@ formStack:
validation: "Stack: {error}" validation: "Stack: {error}"
formStickiness: formStickiness:
title: Sticky Sessions title: Target Routing
detail: Configure the balancer to send requests for a given client to a consistent target container. detail: Configure the balancer to send requests for a given client to a consistent target container or to the same host the balancer is running on..
balancerTarget: Target Container Preference
any: Send requests to a healthy target container on any host.
preferLocal: Prefer containers on the same host as the balancer. (If none are healthy, send to containers on a different host)
onlyLocal: "Use only containers on the same host as the balancer. (If none are healthy, return <code>503</code>)"
sticky: Sticky Sessions
none: None none: None
newCookie: Create new cookie newCookie: Load Balancer defines a stickiness cookie
cookieName: Cookie Name cookieName: Cookie Name
mode: Mode mode: Mode
domain: Domain domain: Domain
@ -2440,7 +2440,7 @@ formStickiness:
indirect: Indirect indirect: Indirect
sendHeader: Send no-cache header sendHeader: Send no-cache header
onPost: Only set cookie on POST onPost: Only set cookie on POST
noPorts: There are no HTTP Listeners configured. noPorts: There are no valid Target Rules configured for a HTTP listener.
placeholder: placeholder:
sticky: e.g. sticky sticky: e.g. sticky
@ -2737,7 +2737,7 @@ k8s:
labelsSection: labelsSection:
kind: Kind kind: Kind
title: Labels title: Labels
detail: These properties show what labels exist. detail: Key/Value data that can be used in Host Scheduling rules or as part of configuring other advanced options.
status: | status: |
{count, plural, {count, plural,
=0 {No labels} =0 {No labels}

2
vendor/icons vendored

@ -1 +1 @@
Subproject commit 178e091d996fe5dd05b2f9c34b447d36c2b2e165 Subproject commit 6f7e52bf171e253ce70ee19ded57e18af60832ad