Upgrade options, balancer

This commit is contained in:
Vincent Fiduccia 2017-05-16 01:17:40 -07:00
parent e12ae6540b
commit edb91c1101
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
21 changed files with 189 additions and 134 deletions

View File

@ -1,4 +1,4 @@
{{new-balancer {{edit-balancer
service=model.service service=model.service
existing=model.existing existing=model.existing
editing=upgrade editing=upgrade

View File

@ -70,6 +70,7 @@ export default Ember.Component.extend(ManageLabels, ContainerChoices,{
isContainerNetwork: Ember.computed.equal('instance.networkMode','container'), isContainerNetwork: Ember.computed.equal('instance.networkMode','container'),
isManagedNetwork: Ember.computed.equal('instance.networkMode','managed'), isManagedNetwork: Ember.computed.equal('instance.networkMode','managed'),
isHostNetwork: Ember.computed.equal('instance.networkMode','host'), isHostNetwork: Ember.computed.equal('instance.networkMode','host'),
isBridgeNetwork: Ember.computed.equal('instance.networkMode','bridge'),
initNetwork: function() { initNetwork: function() {
var isService = this.get('isService')||false; var isService = this.get('isService')||false;

View File

@ -7,7 +7,7 @@
expand=(action expandFn) expand=(action expandFn)
}} }}
<div class="row inline-form"> <div class="row inline-form">
<div class="col {{if (or isContainerNetwork isHostNetwork) 'span-6' (if isManagedNetwork 'span-4' 'span-12')}}"> <div class="col {{if (or isContainerNetwork isHostNetwork isBridgeNetwork) 'span-6' (if isManagedNetwork 'span-4' 'span-12')}}">
<label>{{t 'formNetwork.networkMode.label'}}</label> <label>{{t 'formNetwork.networkMode.label'}}</label>
{{#input-or-display editable=editing value=instance.networkMode}} {{#input-or-display editable=editing value=instance.networkMode}}
{{new-select {{new-select
@ -20,7 +20,7 @@
<p class="help-block">{{t (concat-str 'formNetwork.networkMode' instance.networkMode 'detail' character='.')}}</p> <p class="help-block">{{t (concat-str 'formNetwork.networkMode' instance.networkMode 'detail' character='.')}}</p>
</div> </div>
{{#if (or isContainerNetwork isHostNetwork)}} {{#if (or isContainerNetwork isHostNetwork isBridgeNetwork)}}
<div class="col span-6"> <div class="col span-6">
{{#if isContainerNetwork}} {{#if isContainerNetwork}}
<label>{{t 'formNetwork.container.label'}}</label> <label>{{t 'formNetwork.container.label'}}</label>
@ -34,7 +34,7 @@
value=instance.networkContainerId value=instance.networkContainerId
}} }}
{{/input-or-display}} {{/input-or-display}}
{{else if isHostNetwork}} {{else if (or isHostNetwork isBridgeNetwork)}}
<label>{{t 'formNetwork.dns.label'}}</label> <label>{{t 'formNetwork.dns.label'}}</label>
<div> <div>
{{#input-or-display editable=editing value=dnsDiscovery}} {{#input-or-display editable=editing value=dnsDiscovery}}

View File

@ -0,0 +1,10 @@
import Ember from 'ember';
export default Ember.Component.extend({
service: null,
editing: null,
isUpgrade: null,
choices: null,
classNames: ['accordion-wrapper'],
});

View File

@ -0,0 +1,65 @@
{{#accordion-list-item
title=(t 'formUpgrade.title')
detail=(t 'formUpgrade.detail' appName=settings.appName)
status=status
statusClass=statusClass
expandAll=expandAll
expand=(action expandFn)
}}
{{#input-or-display editable=editing value=service.startFirst}}
<div class="row">
<div class="col span-11-of-23">
<label>{{t 'formUpgrade.behavior'}}</label>
<div class="radio small mt-10">
<label>{{radio-button selection=service.startFirst value=false}} {{t 'formUpgrade.stopFirst.label'}}</label>
<p class="help-block">{{t 'formUpgrade.stopFirst.detail'}}</p>
</div>
</div>
<div class="col span-11-of-23 offset-1-of-23">
<label>&nbsp;</label>
<div class="radio small mt-10">
<label>{{radio-button selection=service.startFirst value=true}} {{t 'formUpgrade.startFirst.label'}}</label>
<p class="help-block">{{t 'formUpgrade.startFirst.detail'}}</p>
</div>
</div>
</div>
{{/input-or-display}}
<hr/>
<div class="row">
<div class="col span-11-of-23">
<label>{{t 'formUpgrade.batchSize.label'}}</label>
{{#input-or-display editable=editing value=service.batchSize}}
<div class="input-group">
{{input-integer min=1 step=100 classNames="form-control" value=service.batchSize}}
<span class="input-group-addon bg-default">{{t 'generic.containers'}}</span>
</div>
<p class="help-block">{{t 'formUpgrade.batchSize.detail'}}</p>
{{/input-or-display}}
</div>
<div class="col span-11-of-23 offset-1-of-23">
<label>{{t 'formUpgrade.interval.label'}}</label>
{{#input-or-display editable=editing value=service.interval}}
<div class="input-group">
{{input-integer min=0 classNames="form-control" value=service.interval}}
<span class="input-group-addon bg-default">{{t 'generic.millisecond'}}</span>
</div>
{{/input-or-display}}
<p class="help-block">{{t 'formUpgrade.interval.detail'}}</p>
</div>
</div>
<hr/>
<div class="row">
<div class="col-23-of-23">
<label>{{t 'formUpgrade.force.label'}}</label>
<p class="help-block">{{t 'formUpgrade.force.detail'}}</p>
@TODO API for force-upgrade
</div>
</div>
{{/accordion-list-item}}

View File

@ -145,6 +145,7 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
index: index, index: index,
name: item.get('name') || intl.t('newContainer.emptySidekick', {num: index+1}), name: item.get('name') || intl.t('newContainer.emptySidekick', {num: index+1}),
enabled: !isUpgrade enabled: !isUpgrade
uiId: item.get('uiId'),
}); });
}); });

View File

@ -4,7 +4,7 @@
<section class="header header-sidekick clearfix"> <section class="header header-sidekick clearfix">
<h2 class="inline-block">{{t headerToken name=configName}}</h2> <h2 class="inline-block">{{t headerToken name=configName}}</h2>
<div class="right-buttons p-0"> <div class="right-buttons p-0">
<button class="btn bg-transparent" {{action "removeSidekick" launchConfigIndex}}>{{t 'newContainer.removeSidekick'}}</button> <button class="btn bg-transparent p-0 text-small text-right" {{action "removeSidekick" launchConfigIndex}}>{{t 'newContainer.removeSidekick'}}</button>
</div> </div>
</section> </section>
{{else}} {{else}}
@ -195,6 +195,17 @@
expandFn=expandFn expandFn=expandFn
}} }}
{{#if (and isService (not isSidekick))}}
{{container/form-upgrade
service=service
editing=true
isUpgrade=isUpgrade
choices=launchConfigChoices
expandAll=al.expandAll
expandFn=expandFn
}}
{{/if}}
{{container/form-volumes {{container/form-volumes
classNames="accordion-wrapper" classNames="accordion-wrapper"
instance=launchConfig instance=launchConfig
@ -228,7 +239,7 @@
{{top-errors errors=errors}} {{top-errors errors=errors}}
{{#save-cancel saveDisabled=noLaunchConfigsEnabled createLabel=(if isUpgrade 'newContainer.saveUpgrade' 'newContainer.saveNew') save="save" cancel="cancel"}} {{#save-cancel saveDisabled=noLaunchConfigsEnabled createLabel=(if isUpgrade 'newContainer.saveUpgrade' 'newContainer.saveNew') save="save" cancel="cancel"}}
{{#if isService}} {{#if isService}}
<button class="btn bg-transparent" {{action "addSidekick"}}>{{t 'newContainer.addSidekick'}}</button> <button class="btn bg-transparent text-right p-0 pt-5 text-small" style="position: absolute; right: 0; margin-top: 8px;" {{action "addSidekick"}}>{{t 'newContainer.addSidekick'}}</button>
{{/if}} {{/if}}
{{/save-cancel}} {{/save-cancel}}
{{/unless}} {{/unless}}

View File

@ -49,10 +49,6 @@ export default Ember.Component.extend(NewOrEdit, {
setLabels(section,labels) { setLabels(section,labels) {
this.set(section+'Labels', labels); this.set(section+'Labels', labels);
}, },
setUpgrade(upgrade) {
this.set('upgradeOptions', upgrade);
},
}, },
headerLabel: function() { headerLabel: function() {

View File

@ -1,47 +1,80 @@
<section class="header clearfix"> <section class="header clearfix">
<h1>{{headerLabel}} {{help-btn link="/cattle/adding-load-balancers/"}}</h1> <h1>{{headerLabel}}</h1>
</section> </section>
<section class="horizontal-form container-fluid"> <div class="row">
{{#liquid-if needsUpgrade}} <div class="col span-11-of-23">
{{form-upgrade {{form-name-description
optionsChanged=(action 'setUpgrade') model=service
namePlaceholder="servicePage.newBalancer.form.name.placeholder"
descriptionPlaceholder="servicePage.newBalancer.form.description.placeholder"
rowClass=""
colClass=""
bothColClass=""
}} }}
{{/liquid-if}} </div>
<div class="{{if needsUpgrade 'hide'}}"> <div class="col span-11-of-23 offset-1-of-23">
{{container/form-scale {{container/form-scale
initialLabels=launchConfig.labels initialLabels=launchConfig.labels
initialScale=service.scale initialScale=service.scale
editing=editing editing=editing
isGlobal=isGlobal isGlobal=isGlobal
isService=true
errors=scaleErrors errors=scaleErrors
setLabels=(action 'setLabels' 'scale') setLabels=(action 'setLabels' 'scale')
setScale=(action 'setScale') setScale=(action 'setScale')
}} }}
{{form-stack
stack=stack
errors=stackErrors
}}
</div> </div>
</div>
<section class="horizontal-form container-fluid">
{{container/form-upgrade
optionsChanged=(action 'setUpgrade')
}}
</section> </section>
<section class="horizontal-form container-fluid"> <section class="horizontal-form container-fluid">
{{form-name-description
model=service
namePlaceholder="servicePage.newBalancer.form.name.placeholder"
descriptionPlaceholder="servicePage.newBalancer.form.description.placeholder"
}}
{{form-balancer-rules {{form-balancer-rules
service=service service=service
}} }}
</section> </section>
{{container/form-scheduling
isService=true
isGlobal=isGlobal
canRequestHost=false
initialHostId=launchConfig.requestedHostId
initialLabels=launchConfig.labels
errors=schedulingErrors
allHosts=allHosts
setLabels=(action 'setLabels' 'scheduling')
}}
{{#advanced-section advanced=false}}
{{#accordion-list as | al expandFn | }}
{{form-user-labels
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
expandAll=al.expandAll
expandFn=expandFn
}}
{{/accordion-list}}
{{/advanced-section}}
{{#select-tab initialTab='ssl' as |component|}} {{#select-tab initialTab='ssl' as |component|}}
<div class="tabs"> <div class="tabs">
<ul class="tab-header" style="display: inline-block" role="tablist"> <ul class="tab-header" style="display: inline-block" role="tablist">
<li role="tab" class="tab" data-section="ssl" {{action "selectTab" "ssl" target=component}}><a href="#">{{t 'newBalancer.tabs.ssl'}}</a></li> <li role="tab" class="tab" data-section="ssl" {{action "selectTab" "ssl" target=component}}><a href="#">{{t 'newBalancer.tabs.ssl'}}</a></li>
<li role="tab" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=component}}><a href="#">{{t 'newBalancer.tabs.stickiness'}}</a></li> <li role="tab" class="tab" data-section="stickiness" {{action "selectTab" "stickiness" target=component}}><a href="#">{{t 'newBalancer.tabs.stickiness'}}</a></li>
<li role="tab" class="tab" data-section="custom" {{action "selectTab" "custom" target=component}}><a href="#">{{t 'newBalancer.tabs.custom'}}</a></li> <li role="tab" class="tab" data-section="custom" {{action "selectTab" "custom" target=component}}><a href="#">{{t 'newBalancer.tabs.custom'}}</a></li>
<li role="tab" class="tab" data-section="labels" {{action "selectTab" "labels" target=component}}><a href="#">{{t 'newBalancer.tabs.labels'}}</a></li>
<li role="tab" class="tab" data-section="scheduling" {{action "selectTab" "scheduling" target=component}}><a href="#">{{t 'newBalancer.tabs.scheduling'}}</a></li>
</ul> </ul>
<div class="tab-content" role="tabpanel"> <div class="tab-content" role="tabpanel">
@ -71,23 +104,9 @@
</div> </div>
<div class="section" data-section="labels"> <div class="section" data-section="labels">
{{form-user-labels
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
}}
</div> </div>
<div class="section" data-section="scheduling"> <div class="section" data-section="scheduling">
{{container/form-scheduling
isService=true
isGlobal=isGlobal
canRequestHost=false
initialHostId=launchConfig.requestedHostId
initialLabels=launchConfig.labels
errors=schedulingErrors
allHosts=allHosts
setLabels=(action 'setLabels' 'scheduling')
}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,44 +0,0 @@
import Ember from 'ember';
export default Ember.Component.extend({
choices : null,
index : null,
batchSize : 1,
interval : 2,
startFirst : false,
init() {
this._super(...arguments);
this.optionsDidChange();
},
optionsDidChange: function() {
this.sendAction('optionsChanged', {
batchSize: parseInt(this.get('batchSize'),10),
intervalMillis: parseInt(this.get('interval'),10)*1000,
startFirst: this.get('startFirst'),
});
}.observes('batchSize','interval','startFirst'),
choicesDidChange: function() {
var index = this.get('index');
var obj = this.get('choices').filterBy('index',index)[0];
if ( !obj || !obj.enabled ) {
var first = this.get('choices').filterBy('enabled',true)[0];
if ( first )
{
this.sendAction('switch', first.index);
}
else
{
this.sendAction('switch', null);
}
}
}.observes('choices.@each.enabled'),
hasSidekicks: function() {
return this.get('choices.length') > 1;
}.property('choices.length'),
});

View File

@ -1,33 +0,0 @@
<div class="row">
<div class="col span-4">
<label>{{t 'formUpgrade.size'}}</label>
{{input-integer min="1" class="form-control" value=batchSize}}
</div>
<div class="col span-4">
<label>{{t 'formUpgrade.interval'}}</label>
<div class="input-group">
{{input-integer class="form-control" value=interval}}
<span class="input-group-addon bg-default">{{t 'formUpgrade.sec'}}</span>
</div>
</div>
<div class="col span-4">
<label>{{t 'formUpgrade.behavior'}}</label>
<div>
<label class="checkbox ml-20" style="color: inherit; text-transform: none;">{{input type="checkbox" checked=startFirst}} {{t 'formUpgrade.startStop'}}</label>
</div>
</div>
</div>
{{#if hasSidekicks}}
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'formUpgrade.whichServices'}}</label>
</div>
<div class="col span-8">
{{#each choices as |choice|}}
<label class="checkbox mr-10" style="color: inherit; text-transform: none;">{{input type="checkbox" checked=choice.enabled}} {{choice.name}}</label>
{{/each}}
</div>
</div>
{{/if}}

View File

@ -15,7 +15,7 @@
</div> </div>
<div class="col span-4 input-group"> <div class="col span-4 input-group">
{{input-integer classNames="form-control" value=inputTimeout style="max-width:120px;"}} {{input-integer classNames="form-control" value=inputTimeout style="max-width:120px;"}}
<div class="input-group-addon bg-default">{{t 'modalContainerStop.uom'}}</div> <div class="input-group-addon bg-default">{{t 'generic.seconds'}}</div>
</div> </div>
</div> </div>
<div class="row text-info mb-20"> <div class="row text-info mb-20">

View File

@ -9,6 +9,7 @@ import { task } from 'ember-concurrency';
export default Ember.Component.extend(NewOrEdit, { export default Ember.Component.extend(NewOrEdit, {
intl: Ember.inject.service(), intl: Ember.inject.service(),
catalog: Ember.inject.service(),
projects: Ember.inject.service(), projects: Ember.inject.service(),
settings: Ember.inject.service(), settings: Ember.inject.service(),
@ -140,9 +141,7 @@ export default Ember.Component.extend(NewOrEdit, {
this.set('stackResource.environment', current); this.set('stackResource.environment', current);
} }
var selectedTemplateModel = yield this.get('store').request({ var selectedTemplateModel = yield this.get('catalog').fetchByUrl(url).then((response) => {
url: url
}).then((response) => {
if (response.questions) { if (response.questions) {
response.questions.forEach((item) => { response.questions.forEach((item) => {
// This will be the component that is rendered to edit this answer // This will be the component that is rendered to edit this answer

View File

@ -10,7 +10,7 @@ export default Ember.Component.extend({
cancelDisabled: false, cancelDisabled: false,
savedLabel: 'saveCancel.saved', savedLabel: 'saveCancel.saved',
forFooter: true, forFooter: true,
classNames: ['text-center' , 'p-20'], classNames: ['text-center', 'pt-20', 'pb-20'],
classNamesBindings: ['forFooter:footer-actions'], classNamesBindings: ['forFooter:footer-actions'],
saving: false, saving: false,

View File

@ -36,8 +36,6 @@
{{/if}} {{/if}}
</div> </div>
<div> <div>
A: {{get subMatches model.id}}<br/>
B: {{model.instances.length}}<br/>
{{#if showInstanceCount}} {{#if showInstanceCount}}
{{#if subMatches}} {{#if subMatches}}
{{#if (lt (get subMatches model.id) model.instances.length)}} {{#if (lt (get subMatches model.id) model.instances.length)}}

View File

@ -1,4 +1,3 @@
import Ember from 'ember';
import Service from 'ui/models/service'; import Service from 'ui/models/service';
export default Service.extend({ export default Service.extend({

View File

@ -7,6 +7,12 @@ export default Resource.extend({
settings: Ember.inject.service(), settings: Ember.inject.service(),
intl: Ember.inject.service(), intl: Ember.inject.service(),
headers: function() {
return {
[C.HEADER.PROJECT_ID]: this.get('projects.current.id')
};
}.property('project.current.id'),
cleanProjectUrl: Ember.computed('links.project', function() { cleanProjectUrl: Ember.computed('links.project', function() {
let projectUrl = this.get('links.project'); let projectUrl = this.get('links.project');
let pattern = new RegExp('^([a-z]+://|//)', 'i'); let pattern = new RegExp('^([a-z]+://|//)', 'i');

View File

@ -2,6 +2,14 @@ import Resource from 'ember-api-store/models/resource';
import C from 'ui/utils/constants'; import C from 'ui/utils/constants';
export default Resource.extend({ export default Resource.extend({
projects: Ember.inject.service(),
headers: function() {
return {
[C.HEADER.PROJECT_ID]: this.get('projects.current.id')
};
}.property('project.current.id'),
filesAsArray: function() { filesAsArray: function() {
var obj = (this.get('files')||{}); var obj = (this.get('files')||{});
var out = []; var out = [];

View File

@ -95,7 +95,7 @@ export default Ember.Service.extend({
} }
let url = this._addLimits(`${this.get('app.catalogEndpoint')}/templates`, qp); let url = this._addLimits(`${this.get('app.catalogEndpoint')}/templates`, qp);
return this.get('store').request({url: url, headers: {[C.HEADER.PROJECT_ID]: this.get('projects.current.id')},}).then((res) => { return this.get('store').request({url: url, headers: {[C.HEADER.PROJECT_ID]: this.get('projects.current.id')}}).then((res) => {
res.catalogId = catalogId; res.catalogId = catalogId;
this.set('templateCache', res); this.set('templateCache', res);
return this.filter(res, params.category, templateBase, plusInfra); return this.filter(res, params.category, templateBase, plusInfra);
@ -108,6 +108,10 @@ export default Ember.Service.extend({
}); });
}, },
fetchByUrl(url) {
return this.get('store').request({url: url, headers: {[C.HEADER.PROJECT_ID]: this.get('projects.current.id')}});
},
filter(data, category, templateBase, plusInfra) { filter(data, category, templateBase, plusInfra) {
let bases = []; let bases = [];

View File

@ -1,5 +1,6 @@
import Ember from 'ember'; import Ember from 'ember';
import C from 'ui/utils/constants'; import C from 'ui/utils/constants';
import Util from 'ui/utils/util';
export default Ember.Service.extend({ export default Ember.Service.extend({
cookies: Ember.inject.service(), cookies: Ember.inject.service(),

View File

@ -13,8 +13,9 @@ generic:
cancel: Cancel cancel: Cancel
closeModal: Close closeModal: Close
command: Command command: Command
confirm: Confirm
collapseAll: Collapse All collapseAll: Collapse All
confirm: Confirm
containers: Containers
created: Created created: Created
createdDate: "Created {date}" createdDate: "Created {date}"
default: Default default: Default
@ -42,6 +43,7 @@ generic:
loading: "Loading..." loading: "Loading..."
megabyte: 'MB' megabyte: 'MB'
mibibyte: 'MiB' mibibyte: 'MiB'
millisecond: 'ms'
missing: "*%MISSING%*" missing: "*%MISSING%*"
moreActions: More Actions moreActions: More Actions
na: 'n/a' na: 'n/a'
@ -55,6 +57,7 @@ generic:
saved: Saved saved: Saved
saving: Saving saving: Saving
search: Search search: Search
seconds: seconds
select: Select select: Select
service: Service service: Service
stack: Stack stack: Stack
@ -2469,12 +2472,24 @@ formUserLabels:
protip: "ProTip: Paste one or more lines of key=value pairs into any key field for easy bulk entry." protip: "ProTip: Paste one or more lines of key=value pairs into any key field for easy bulk entry."
formUpgrade: formUpgrade:
size: Batch Size title: Upgrade
interval: Batch Interval detail: Configure how containers are replaced when performing an upgrade.
sec: sec batchSize:
behavior: Start Behavior label: Batch Size
startStop: Start before Stopping detail: Up to this many containers will be replaced at once.
whichServices: Which Services interval:
label: Batch Interval
detail: After finishing a batch of containers, wait this long before starting the next batch
behavior: Replacement Behavior
startFirst:
label: Start new, then stop old
detail: Start new containers before stopping the old ones. If the service publishes a port, there must be enough eligible hosts availeblt to run Batch Size new containers, because the old containers are still actively using the ports.
stopFirst:
label: Stop old, then start new
detail: Stop the old containers (up to the Batch Size), then start new ones. This allows the reuse of published ports. Adjust Batch Size to ensure that you keep enough active capacity to run your application.
force:
label: Force Redeploy
detail: During an upgrade, containers are normally only replaced if part of their definition has changed. To force one to redeploy for this upgrade, select it here.
formValueArray: formValueArray:
addActionLabel: Add Value addActionLabel: Add Value
@ -3190,7 +3205,6 @@ modalAuditlogInfo:
response: "Response Object:" response: "Response Object:"
modalContainerStop: modalContainerStop:
uom: seconds
header: "Are you sure you want to stop" header: "Are you sure you want to stop"
helpText: "The container will be forcibly terminated if it does not stop itself before the timeout expires" helpText: "The container will be forcibly terminated if it does not stop itself before the timeout expires"
protip: "ProTip: Hold the {key} key while clicking stop to bypass this confirmation." protip: "ProTip: Hold the {key} key while clicking stop to bypass this confirmation."
@ -3415,7 +3429,7 @@ newContainer:
keyPlaceholder: e.g. FOO keyPlaceholder: e.g. FOO
valueLabel: Value valueLabel: Value
valuePlaceholder: e.g. bar valuePlaceholder: e.g. bar
emptyPrimaryService: "(Primary Service)" emptyPrimaryService: "(Primary)"
emptySidekick: "(Sidekick #{num})" emptySidekick: "(Sidekick #{num})"
addSidekickContainer: Add Sidekick Container addSidekickContainer: Add Sidekick Container
addSidekickVm: Add Sidekick VM addSidekickVm: Add Sidekick VM