Add scheduler rules on containers and services

This commit is contained in:
Vincent Fiduccia 2015-06-03 18:30:25 -07:00
parent 188211a163
commit 2aba2351f5
24 changed files with 550 additions and 50 deletions

View File

@ -1,4 +1,5 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
export default Ember.Component.extend({
model: null,
@ -8,7 +9,7 @@ export default Ember.Component.extend({
var obj = this.get('model')||{};
var keys = Ember.keys(obj);
keys.forEach(function(key) {
var isUser = key.indexOf('io.rancher') !== 0;
var isUser = key.indexOf(C.LABEL.SYSTEM_PREFIX) !== 0;
out.push(Ember.Object.create({
key: key,
value: obj[key],

View File

@ -4,10 +4,10 @@ export default Ember.Component.extend({
tagName: 'input',
type: 'radio',
disabled: false,
attributeBindings: ['name', 'type', 'value', 'checked:checked', 'disabled:disabled'],
attributeBindings: ['name', 'type', 'checked:checked', 'disabled:disabled'],
click : function() {
this.set('selection', this.$().val());
this.set('selection', this.get('value'));
},
checked : function() {

View File

@ -0,0 +1,252 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
function splitEquals(str) {
var idx = str.indexOf('=');
if ( idx === -1 )
{
return null;
}
return [ str.substr(0,idx) , str.substr(idx+1) ];
}
export default Ember.Component.extend({
rule: null,
instance: null,
allHosts: null,
tagName: 'TR',
kind: null,
suffix: null,
userKey: null,
userValue: null,
actions: {
setKey: function(key) {
this.set('userKey', key);
},
setValue: function(value) {
this.set('userValue', value);
},
remove: function() {
this.sendAction('remove', this.get('rule'));
}
},
init: function() {
this._super();
var key = this.get('rule.key')||'';
var value = this.get('rule.value')||'';
var splitValue = splitEquals(value);
var match = key.match(/((_soft)?(_ne)?)$/);
if ( match )
{
this.set('suffix', match[1]);
key = key.substr(0, key.length - match[1].length);
}
else
{
this.set('suffix','');
}
// Convert from an existing key into the 4 fields
switch ( key )
{
case C.LABEL.SCHED_CONTAINER:
this.setProperties({
kind: 'container_name',
userKey: '',
userValue: value,
});
break;
case C.LABEL.SCHED_CONTAINER_LABEL:
if ( splitValue[0] === C.LABEL.SERVICE_NAME )
{
this.setProperties({
kind: 'service_name',
userKey: '',
userValue: splitValue[1],
});
}
else
{
this.setProperties({
kind: 'container_label',
userKey: splitValue[0],
userValue: splitValue[1],
});
}
break;
case C.LABEL.SCHED_HOST_LABEL:
this.setProperties({
kind: 'host_label',
userKey: splitValue[0],
userValue: splitValue[1],
});
break;
}
},
valuesChanged: function() {
var key = '';
var value = null;
var userKey = this.get('userKey')||'';
var userValue = this.get('userValue')||'';
switch ( this.get('kind') )
{
case 'host_label':
key = C.LABEL.SCHED_HOST_LABEL;
if ( userKey && userValue )
{
value = encodeURIComponent(userKey) + '=' + encodeURIComponent(userValue);
}
break;
case 'container_label':
key = C.LABEL.SCHED_CONTAINER_LABEL;
if ( userKey && userValue )
{
value = encodeURIComponent(userKey) + '=' + encodeURIComponent(userValue);
}
break;
case 'container_name':
key = C.LABEL.SCHED_CONTAINER;
if ( userValue )
{
value = encodeURIComponent(userValue);
}
break;
case 'service_name':
key = C.LABEL.SCHED_CONTAINER_LABEL;
if ( userValue )
{
value = encodeURIComponent(C.LABEL.SERVICE_NAME) + '=' + encodeURIComponent(userValue);
}
break;
}
key += this.get('suffix');
Ember.setProperties(this.get('rule'),{
key: key,
value: value
});
}.observes('kind','suffix','userKey','userValue'),
schedulingRuleSuffixChoices: [
{label: 'must', value: ''},
{label: 'should', value: '_soft'},
{label: 'should not', value: '_soft_ne'},
{label: 'must not', value: '_ne'},
],
schedulingRuleKindChoices: [
{label: 'host label', value: 'host_label'},
{label: 'container with label', value: 'container_label'},
{label: 'service with the name', value: 'service_name'},
{label: 'container with the name', value: 'container_name'},
],
hostLabelKeyChoices: function() {
var out = [];
this.get('allHosts').forEach((host) => {
var keys = Ember.keys(host.get('labels')||{}).filter((key) => {
return key.indexOf(C.LABEL.SYSTEM_PREFIX) !== 0;
});
out.pushObjects(keys);
});
return out.sort().uniq();
}.property('allHosts.@each.labels'),
hostLabelValueChoices: function() {
var key = this.get('userKey');
var out = [];
this.get('allHosts').forEach((host) => {
var label = (host.get('labels')||{})[key];
if ( label )
{
var parts = label.split(/\s*,\s*/);
out.pushObjects(parts);
}
});
return out.sort().uniq();
}.property('userKey','allHosts.@each.labels'),
allContainers: function() {
var out = [];
this.get('allHosts').map((host) => {
var containers = (host.get('instances')||[]).filter(function(instance) {
return instance.get('kind') === 'container' &&
!instance.get('systemContainer');
});
out.pushObjects(containers);
});
return out.sortBy('name','id').uniq();
}.property('allHosts.@each.instancesUpdated'),
containerLabelKeyChoices: function() {
var out = [];
this.get('allContainers').forEach((container) => {
var keys = Ember.keys(container.get('labels')||{}).filter((key) => {
return key.indexOf(C.LABEL.SYSTEM_PREFIX) !== 0;
});
out.pushObjects(keys);
});
return out.sort().uniq();
}.property('allContainers.@each.labels'),
containerLabelValueChoices: function() {
var key = this.get('userKey');
var out = [];
this.get('allContainers').forEach((container) => {
var label = (container.get('labels')||{})[key];
if ( label )
{
var parts = label.split(/\s*,\s*/);
out.pushObjects(parts);
}
});
return out.sort().uniq();
}.property('userKey','allContainers.@each.labels'),
containerValueChoices: function() {
var out = [];
this.get('allContainers').forEach((container) => {
var name = container.get('name');
if ( name )
{
out.push(name);
}
});
return out.sort().uniq();
}.property('allContainers.@each.name'),
serviceValueChoices: function() {
var out = [];
this.get('allContainers').forEach((container) => {
var label = (container.get('labels')||{})[C.LABEL.SERVICE_NAME];
if ( label )
{
var parts = label.split(/\s*,\s*/);
out.pushObjects(parts);
}
});
return out.sort().uniq();
}.property('allContainers.@each.labels'),
});

View File

@ -0,0 +1,125 @@
<td><div class="form-control-static input-sm">The host</div></td>
<td>
{{view "select"
class="form-control input-sm"
content=schedulingRuleSuffixChoices
value=suffix
optionValuePath="content.value"
optionLabelPath="content.label"
}}
</td>
<td><div class="form-control-static text-center input-sm">have a</div></td>
<td>
{{view "select"
class="form-control input-sm"
content=schedulingRuleKindChoices
value=kind
optionValuePath="content.value"
optionLabelPath="content.label"
}}
</td>
<td>
{{#if (not (or (eq kind "service_name") (eq kind "container_name")))}}
<div class="form-control-static text-center input-sm">of</div>
{{/if}}
</td>
<td>
{{#if (eq kind "host_label")}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each key in hostLabelKeyChoices}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
{{#if (eq kind "container_label")}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each key in containerLabelKeyChoices}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
</td>
<td>
{{#if (not (or (eq kind "service_name") (eq kind "container_name")))}}
<div class="form-control-static text-center input-sm">=</div>
{{/if}}
</td>
<td>
{{#if (eq kind "host_label")}}
<div {{bind-attr class="hostLabelValueChoices:input-group"}}>
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if hostLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each value in hostLabelValueChoices}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{/if}}
{{#if (eq kind "container_label")}}
<div {{bind-attr class="containerLabelValueChoices:input-group"}}>
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each value in containerLabelValueChoices}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{/if}}
{{#if (eq kind "service_name")}}
<div {{bind-attr class="serviceValueChoices:input-group"}}>
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if serviceValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each value in serviceValueChoices}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{/if}}
{{#if (eq kind "container_name")}}
<div {{bind-attr class="containerValueChoices:input-group"}}>
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each value in containerValueChoices}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{/if}}
</td>
<td class="text-right">
<div class="form-control-static input-sm">
<button {{action "remove"}} class="btn-circle-x" type="button" tabindex="-1"></button>
</div>
</td>

View File

@ -12,6 +12,7 @@ export default Ember.View.extend({
addDnsSearch: addAction('addDnsSearch', '.dns-search-value'),
addDevice: addAction('addDevice', '.device-host'),
addLabel: addAction('addLabel', '.label-key'),
addSchedulingRule: addAction('addSchedulingRule', '.schedule-rule'),
selectTab: function(name) {
this.set('context.tab',name);

View File

@ -131,7 +131,15 @@ export default Ember.Mixin.create(Cattle.NewOrEditMixin, EditHealthCheck, EditLa
ary.removeObject(item);
}
});
}
},
addSchedulingRule: function() {
this.send('addSystemLabel');
},
removeSchedulingRule: function(obj) {
this.send('removeLabel', obj);
},
},
// ----------------------------------
@ -161,6 +169,7 @@ export default Ember.Mixin.create(Cattle.NewOrEditMixin, EditHealthCheck, EditLa
this.initMemory();
this.initLabels();
this.initHealthCheck();
this.initScheduling();
}
},
@ -835,6 +844,36 @@ export default Ember.Mixin.create(Cattle.NewOrEditMixin, EditHealthCheck, EditLa
}.observes('strEntryPoint'),
// ----------------------------------
// Scheduling
// ----------------------------------
initScheduling: function() {
if ( this.get('instance.requestedHostId') )
{
this.set('isRequestedHost',true);
}
else
{
this.set('isRequestedHost',false);
}
// @TODO import existing for clone
},
isRequestedHost: null,
isRequestedHostDidChange: function() {
if ( this.get('isRequestedHost') )
{
if ( !this.get('instance.requestedHostId') )
{
this.set('instance.requestedHostId', this.get('hostChoices.firstObject.id'));
}
}
else
{
this.set('instance.requestedHostId', null);
}
}.observes('isRequestedHost'),
// ----------------------------------
// Save
// ----------------------------------

View File

@ -1,4 +1,5 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
export default Ember.Mixin.create({
labelResource: Ember.computed.alias('primaryResource'),
@ -82,6 +83,10 @@ export default Ember.Mixin.create({
return (this.get('labelArray')||[]).filterProperty('isUser',true);
}.property('labelArray.@each.isUser'),
systemLabelArray: function() {
return (this.get('labelArray')||[]).filterProperty('isUser',false);
}.property('labelArray.@each.isUser'),
initFields: function() {
this._super();
this.initLabels();
@ -95,7 +100,7 @@ export default Ember.Mixin.create({
out.push(Ember.Object.create({
key: key,
value: obj[key],
isUser: key.indexOf('io.rancher') !== 0,
isUser: key.indexOf(C.LABEL.SYSTEM_PREFIX) !== 0,
}));
});
@ -108,7 +113,11 @@ export default Ember.Mixin.create({
this.get('labelArray').forEach(function(row) {
if ( row.key )
{
out[row.key] = row.value;
// System labels have to have a value before they're added, users ones can be just key.
if ( row.isUser || row.value )
{
out[row.key] = row.value;
}
}
});
this.set('labelResource.labels', out);

View File

@ -77,18 +77,22 @@ export default Ember.Mixin.create(EditLabels, {
// ----------------------------------
// Scheduling
// ----------------------------------
isScalePlural: Ember.computed.gt('service.scale', 1),
isGlobalStr: null,
isGlobal: Ember.computed.equal('isGlobalStr','yes'),
isGlobal: null,
initScheduling: function() {
var existing = this.getLabel(C.LABEL.SCHED_GLOBAL);
this.set('isGlobalStr', (!!existing ? 'yes' : 'no'));
this.set('isGlobal', !!existing);
this._super();
if ( this.get('isRequestedHost') )
{
this.set('isGlobal', false);
}
},
globalDidChange: function() {
if ( this.get('isGlobal') )
{
this.setLabel(C.LABEL.SCHED_GLOBAL,'true');
this.set('isRequestedHost', false);
}
else
{
@ -96,6 +100,13 @@ export default Ember.Mixin.create(EditLabels, {
}
}.observes('isGlobal'),
isRequestedHostDidChangeGlobal: function() {
if ( this.get('isRequestedHost') )
{
this.set('isGlobal', false);
}
}.observes('isRequestedHost'),
// ----------------------------------
// Save
// ----------------------------------

View File

@ -1,4 +1,5 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
export default Ember.Mixin.create({
labelResource: null,
@ -8,7 +9,7 @@ export default Ember.Mixin.create({
var obj = this.get('labelResource.labels')||{};
var keys = Ember.keys(obj).sort();
keys.forEach(function(key) {
var isUser = key.indexOf('io.rancher') !== 0;
var isUser = key.indexOf(C.LABEL.SYSTEM_PREFIX) !== 0;
out.push(Ember.Object.create({
key: key,
value: obj[key],

View File

@ -1,4 +1,5 @@
import Cattle from 'ui/utils/cattle';
import C from 'ui/utils/constants';
var Service = Cattle.TransitioningResource.extend({
type: 'service',
@ -9,9 +10,12 @@ var Service = Cattle.TransitioningResource.extend({
}.observes('consumedservices.@each.{id,name,state}'),
healthState: function() {
var isGlobal = Object.keys(this.get('labels')||{}).indexOf(C.LABEL.SCHED_GLOBAL) >= 0;
var instances = this.get('instances')||[];
// Get the state of each instance
var healthy = 0;
(this.get('instances')||[]).forEach((instance) => {
instances.forEach((instance) => {
var resource = instance.get('state');
var health = instance.get('healthState');
@ -21,7 +25,7 @@ var Service = Cattle.TransitioningResource.extend({
}
});
if ( healthy >= this.get('scale') )
if ( (isGlobal && healthy >= instances.get('length')) || (!isGlobal && healthy >= this.get('scale')) )
{
return 'healthy';
}
@ -34,6 +38,7 @@ var Service = Cattle.TransitioningResource.extend({
combinedState: function() {
var service = this.get('state');
var health = this.get('healthState');
if ( ['active','updating-active'].indexOf(service) === -1 )
{
// If the service isn't active, return its state

View File

@ -10,7 +10,7 @@
</div>
<div class="col-sm-3 col-md-2">
<div class="radio small">
<label>{{radio-button selection=isGlobalStr value="no"}} Run {{service.scale}} container{{#if isScalePlural}}s{{/if}}</label>
<label>{{radio-button selection=isGlobal value=false}} Run {{service.scale}} container{{#if (not (eq service.scale 1))}}s{{/if}}</label>
</div>
</div>
<div class="col-sm-9 col-md-6">
@ -20,7 +20,7 @@
<div class="row">
<div class="col-sm-12 col-md-8 col-md-push-2">
<div class="radio small">
<label>{{radio-button selection=isGlobalStr value="yes"}} Always run one instance of this container on every host</label>
<label>{{radio-button selection=isGlobal value=true}} Always run one instance of this container on every host</label>
</div>
</div>
</div>

View File

@ -5,5 +5,6 @@ export default NewContainerView.extend({
actions: {
addVolumeFromService: addAction('addVolumeFromService', '.volumefromservice-container'),
addServiceLink: addAction('addServiceLink', '.service-link'),
addSchedulingRule: addAction('addSchedulingRule', '.schedule-rule'),
},
});

View File

@ -174,6 +174,8 @@ fieldset[disabled] .btn {
}
.table {
margin-bottom: 0;
& > THEAD > TR > TH,
& > THEAD > TR > TD,
& > TBODY > TR > TH,
@ -418,3 +420,8 @@ FORM LABEL,
.help-block {
color: #444;
}
.form-group {
padding-bottom: 15px;
margin-bottom: 0;
}

View File

@ -631,7 +631,7 @@ ASIDE {
}
HR {
margin: 0 0 15px 0;
margin: 8px 0 8px 0;
}
}

View File

@ -7,7 +7,7 @@
</div>
</div>
<div class="row form-group">
<div class="row">
<div class="col-sm-12 col-md-2 form-label">
<label for="description">Description</label>
</div>

View File

@ -1,10 +1,10 @@
<div class="row form-group">
<div class="row">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">Service Links</label>
<label>Service Links</label>
</div>
<div class="col-sm-12 col-md-8">
<div class="form-control-static">
<div>
{{#if serviceChoices.length}}
<button class="btn-circle-plus" {{action "addServiceLink" target="view"}}></button>
{{else}}

View File

@ -11,6 +11,7 @@
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
<li role="presentation" class="tab" data-section="security" {{action "selectTab" "security" target=view}}><a>Security/Host</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>
@ -46,11 +47,9 @@
</div>
</div>
{{#if isService}}
<div class="section" data-section="scheduling">
{{partial "container/new-scheduling"}}
</div>
{{/if}}
<div class="section" data-section="scheduling">
{{partial "container/new-scheduling"}}
</div>
</section>
</div>

View File

@ -120,7 +120,7 @@
</tr>
{{/each}}
</table>
<div class="text-muted" style="font-size: 12px; margin-top: -20px; margin-bottom: 12px;">
<div class="text-muted" style="font-size: 12px; margin-bottom: 12px;">
ProTip: Paste one or more lines of name=value pairs into any name field for easy bulk entry.
</div>
{{/if}}

View File

@ -1,4 +1,4 @@
<div class="row form-group">
<div class="row">
<div class="col-sm-12 col-md-2 form-label">
<label for="userImageUuid" class="form-control-static">Select Image</label>
</div>

View File

@ -0,0 +1,61 @@
<div class="form-group">
<div class="radio">
<label class="form-control-static">{{radio-button selection=isRequestedHost value=true}}
{{#if isService}}
Run <b>all</b> containers on a specific host
{{else}}
Run on a specific host
{{/if}}</label>
{{#if isRequestedHost}}:
{{view "select"
class="form-control"
content=hostChoices
value=instance.requestedHostId
optionValuePath="content.id"
optionLabelPath="content.name"
disabled=(not isRequestedHost)
style="display: inline-block; width: auto;"
}}
{{/if}}
</div>
<div class="radio">
<label>{{radio-button selection=isRequestedHost value=false}}
{{#if isService}}
Automatically pick hosts for each container matching scheduling rules :
{{else}}
Automatically pick a host matching scheduling rules :
{{/if}}
</label>
</div>
{{#unless isRequestedHost}}
<div class="form-control-static">
<button class="btn-circle-plus" {{action "addSchedulingRule" target="view"}}></button>
</div>
{{#if systemLabelArray.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 rule in labelArray}}
{{#unless rule.isUser}}
{{scheduling-rule-row rule=rule allHosts=allHosts remove="removeSchedulingRule"}}
{{/unless}}
{{/each}}
</tbody>
</table>
{{/if}}
{{/unless}}
</div>

View File

@ -1,16 +1,11 @@
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label for="requestedHostId" class="form-control-static">Host</label>
<label for="privileged" class="form-control-static">Privileged</label>
</div>
<div class="col-sm-12 col-md-3 form-label">
{{view "select"
prompt="Automatically pick a host"
class="form-control"
content=hostChoices
value=instance.requestedHostId
optionValuePath="content.id"
optionLabelPath="content.name"
}}
<div class="checkbox form-control-static">
<label for="privileged">{{input type="checkbox" id="privileged" checked=instance.privileged}} Full access to the host</label>
</div>
</div>
<div class="col-sm-12 col-md-2 form-label">
@ -41,18 +36,6 @@
</div>
</div>
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label for="privileged" class="form-control-static">Privileged</label>
</div>
<div class="col-sm-12 col-md-8">
<div class="checkbox form-control-static">
<label for="privileged">{{input type="checkbox" id="privileged" checked=instance.privileged}} Give the container full access to the host</label>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">Capabilities</label>

View File

@ -30,7 +30,7 @@
</tr>
{{/each}}
</table>
<div class="text-muted" style="font-size: 12px; margin-top: -20px; margin-bottom: 12px;">
<div class="text-muted" style="font-size: 12px; margin-bottom: 12px;">
ProTip: Paste one or more lines of key=value pairs into any key field for easy bulk entry.
</div>
{{/if}}

View File

@ -75,7 +75,11 @@ export default {
},
LABEL: {
SYSTEM_PREFIX: 'io.rancher.',
SERVICE_NAME: 'io.rancher.service.name',
SCHED_GLOBAL: 'io.rancher.scheduler.global',
SCHED_CONTAINER: 'io.rancher.scheduler.affinity:container',
SCHED_HOST_LABEL: 'io.rancher.scheduler.affinity:host_label',
SCHED_CONTAINER_LABEL: 'io.rancher.scheduler.affinity:container_label',
},
};

View File

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "0.23.0-rc1",
"version": "0.23.0-rc4",
"private": true,
"directories": {
"doc": "doc",
@ -38,6 +38,7 @@
"ember-cli-uglify": "1.0.1",
"ember-export-application-global": "^1.0.2",
"ember-inline-svg": "^0.1.2",
"ember-truth-helpers": "0.0.5",
"express": "^4.8.5",
"forever-agent": "^0.5.2",
"glob": "^5.0.3",