Merge pull request #3184 from westlywright/cluster.templates.bugs

Cluster Templates
This commit is contained in:
Westly Wright 2019-08-02 14:49:05 -07:00 committed by GitHub
commit dde3c3edbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 278 additions and 165 deletions

View File

@ -1,7 +1,7 @@
import Resource from '@rancher/ember-api-store/models/resource'; import Resource from '@rancher/ember-api-store/models/resource';
import { reference } from '@rancher/ember-api-store/utils/denormalize'; import { reference } from '@rancher/ember-api-store/utils/denormalize';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { computed, set } from '@ember/object'; import { computed, get, set } from '@ember/object';
import { alias } from '@ember/object/computed'; import { alias } from '@ember/object/computed';
export default Resource.extend({ export default Resource.extend({
@ -114,12 +114,14 @@ export default Resource.extend({
validationErrors() { validationErrors() {
let errors = []; let errors = [];
if (!get(this, 'name')) {
errors.push('Revision name is required');
}
if (errors.length > 0) { if (errors.length > 0) {
return errors; return errors;
} }
errors = this._super(...arguments);
return errors; return errors;
}, },
}); });

View File

@ -9,7 +9,8 @@
"ember-auto-import": "*", "ember-auto-import": "*",
"ember-cli-htmlbars": "*", "ember-cli-htmlbars": "*",
"ember-href-to": "*", "ember-href-to": "*",
"ember-cli-babel": "*" "ember-cli-babel": "*",
"ember-deep-set": "*"
}, },
"ember-addon": { "ember-addon": {
"paths": [ "paths": [

View File

@ -21,6 +21,7 @@ import ManageLabels from 'shared/mixins/manage-labels';
import { typeOf } from '@ember/utils'; import { typeOf } from '@ember/utils';
import Semver, { major, minor } from 'semver'; import Semver, { major, minor } from 'semver';
import { on } from '@ember/object/evented'; import { on } from '@ember/object/evented';
import deepSet from 'ember-deep-set';
const EXCLUDED_KEYS = ['extra_args']; const EXCLUDED_KEYS = ['extra_args'];
@ -66,62 +67,63 @@ const {
} = C; } = C;
export default InputTextFile.extend(ManageLabels, ClusterDriver, { export default InputTextFile.extend(ManageLabels, ClusterDriver, {
globalStore: service(), globalStore: service(),
settings: service(), settings: service(),
growl: service(), growl: service(),
intl: service(), intl: service(),
clusterTemplates: service(), clusterTemplates: service(),
access: service(), access: service(),
router: service(), router: service(),
layout, layout,
authChoices: AUTHCHOICES, authChoices: AUTHCHOICES,
ingressChoices: INGRESSCHOICES, ingressChoices: INGRESSCHOICES,
availableStrategies: AVAILABLE_STRATEGIES, availableStrategies: AVAILABLE_STRATEGIES,
ingornedRkeOverrides: CLUSTER_TEMPLATE_IGNORED_OVERRIDES, ingornedRkeOverrides: CLUSTER_TEMPLATE_IGNORED_OVERRIDES,
configField: 'rancherKubernetesEngineConfig', configField: 'rancherKubernetesEngineConfig',
registry: 'default', registry: 'default',
accept: '.yml, .yaml', accept: '.yml, .yaml',
backupStrategy: 'local', backupStrategy: 'local',
overrideCreatLabel: null, overrideCreatLabel: null,
loading: false, loading: false,
pasteOrUpload: false, pasteOrUpload: false,
model: null, model: null,
initialVersion: null, initialVersion: null,
registryUrl: null, registryUrl: null,
registryUser: null, registryUser: null,
registryPass: null, registryPass: null,
clusterOptErrors: null, clusterOptErrors: null,
nodeNameErrors: null, nodeNameErrors: null,
existingNodes: null, existingNodes: null,
initialNodeCounts: null, initialNodeCounts: null,
step: 1, step: 1,
token: null, token: null,
taints: null, taints: null,
labels: null, labels: null,
etcd: false, etcd: false,
controlplane: false, controlplane: false,
worker: true, worker: true,
defaultDockerRootDir: null, defaultDockerRootDir: null,
nodePoolErrors: null, nodePoolErrors: null,
windowsEnable: false, windowsEnable: false,
isLinux: true, isLinux: true,
weaveCustomPassword: false, weaveCustomPassword: false,
clusterTemplateCreate: false, clusterTemplateCreate: false,
clusterTemplateQuestions: null, clusterTemplateQuestions: null,
forceExpandOnInit: false, forceExpandOnInit: false,
forceExpandAll: false, forceExpandAll: false,
applyClusterTemplate: null, applyClusterTemplate: null,
useClusterTemplate: false, useClusterTemplate: false,
clusterTemplateRevisionId: null, clusterTemplateRevisionId: null,
clusterTemplatesEnforced: false, clusterTemplatesEnforced: false,
isNew: equal('mode', 'new'), selectedClusterTemplateId: null,
isEdit: equal('mode', 'edit'), isNew: equal('mode', 'new'),
notView: or('isNew', 'isEdit'), isEdit: equal('mode', 'edit'),
clusterState: alias('model.originalCluster.state'), notView: or('isNew', 'isEdit'),
clusterState: alias('model.originalCluster.state'),
// Custom stuff // Custom stuff
isCustom: equal('nodeWhich', 'custom'), isCustom: equal('nodeWhich', 'custom'),
@ -133,8 +135,9 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
if (!this.useClusterTemplate && this.clusterTemplateRevisionId) { if (!this.useClusterTemplate && this.clusterTemplateRevisionId) {
setProperties(this, { setProperties(this, {
useClusterTemplate: true, useClusterTemplate: true,
forceExpandOnInit: true, forceExpandOnInit: true,
selectedClusterTemplateId: this.model.clusterTemplateRevision.clusterTemplateId,
}) })
} }
@ -413,6 +416,14 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
return [...(errors || []), ...(clusterErrors || []), ...(clusterOptErrors || []), ...(otherErrors || [])]; return [...(errors || []), ...(clusterErrors || []), ...(clusterOptErrors || []), ...(otherErrors || [])];
}), }),
filteredClusterTemplates: computed('model.clusterTemplates.@each.{id,state,name,members}', function() {
return get(this, 'model.clusterTemplates');
}),
filteredTemplateRevisions: computed('selectedClusterTemplateId', 'model.clusterTemplateRevisions.@each.{id,state,name,members}', function() {
return get(this, 'model.clusterTemplateRevisions').filterBy('enabled').filterBy('clusterTemplateId', this.selectedClusterTemplateId);
}),
allTemplates: computed('model.clusterTemplates.[]', 'model.clusterTemplateRevisions.[]', function() { allTemplates: computed('model.clusterTemplates.[]', 'model.clusterTemplateRevisions.[]', function() {
const remapped = []; const remapped = [];
let { clusterTemplates, clusterTemplateRevisions } = this.model; let { clusterTemplates, clusterTemplateRevisions } = this.model;
@ -767,7 +778,12 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
}, },
willSave() { willSave() {
const { cluster, configField: field } = this; const {
applyClusterTemplate,
cluster,
configField: field,
} = this;
let ok = true;
this.checkKubernetesVersionSemVer(); this.checkKubernetesVersionSemVer();
@ -779,19 +795,6 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
} }
} }
if (typeOf(cluster.clearProvidersExcept) === 'function' || this.applyClusterTemplate && typeOf(cluster.buildClusterAnswersFromConfig) === 'function') {
if (this.applyClusterTemplate) {
// need to add overrides + user entry to answers on cluster, drop rkeconfig
let answers = this.buildClusterAnswersFromConfig(cluster, get(this, 'model.clusterTemplateRevision.questions'));
this.cluster.clearConfigFieldsForClusterTemplate();
set(cluster, 'answers', { values: answers });
} else {
cluster.clearProvidersExcept(field);
}
}
if (get(cluster, 'localClusterAuthEndpoint')) { if (get(cluster, 'localClusterAuthEndpoint')) {
if (!get(cluster, 'rancherKubernetesEngineConfig') || isEmpty(get(cluster, 'rancherKubernetesEngineConfig'))) { if (!get(cluster, 'rancherKubernetesEngineConfig') || isEmpty(get(cluster, 'rancherKubernetesEngineConfig'))) {
delete cluster.localClusterAuthEndpoint; delete cluster.localClusterAuthEndpoint;
@ -800,22 +803,79 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
set(this, 'errors', null); set(this, 'errors', null);
// TODO ok = this.validate();
if (this.applyClusterTemplate || this.clusterTemplateCreate) {
return true; if (ok) {
} else { if (typeOf(cluster.clearProvidersExcept) === 'function' || applyClusterTemplate && typeOf(this.buildClusterAnswersFromConfig) === 'function') {
return this.validate(); if (applyClusterTemplate) {
let questions = get(this, 'model.clusterTemplateRevision.questions') || [];
let answers = [];
if (questions.length > 0) {
answers = this.buildClusterAnswersFromConfig(cluster, questions);
let errors = this.checkRequiredQuestionsHaveAnswers(questions, answers);
if (isEmpty(errors)) {
set(cluster, 'answers', { values: answers });
this.cluster.clearConfigFieldsForClusterTemplate();
} else {
set(this, 'errors', errors);
return false;
}
}
} else {
cluster.clearProvidersExcept(field);
}
}
} }
return ok;
},
checkRequiredQuestionsHaveAnswers(questions, answers) {
const { intl } = this;
const required = questions.filterBy('required', true);
const errors = [];
if (questions.length > 0 && required.length > 0) {
required.forEach((rq) => {
if (!answers[rq.variable]) {
errors.push(intl.t('validation.required', { key: rq.variable }));
}
})
}
return errors;
}, },
validate() { validate() {
this._super(...arguments); this._super(...arguments);
let errors = []; let errors = [];
let config = get(this, `config`); let { config, intl } = this;
if ( !get(this, 'isCustom') ) {
errors.pushObjects(get(this, 'nodePoolErrors')); if (this.clusterTemplateCreate) {
if (this.model.clusterTemplateRevision) {
errors.pushObjects(this.model.clusterTemplateRevision.validationErrors());
}
} else {
if ( !get(this, 'isCustom') ) {
errors.pushObjects(get(this, 'nodePoolErrors'));
}
if ( get(config, 'cloudProvider.name') === 'azure' ) {
Object.keys(AzureInfo).forEach((key) => {
if ( get(AzureInfo, `${ key }.required`) && !get(config, `cloudProvider.azureCloudProvider.${ key }`)) {
if ( this.isNew || this.isEdit && key !== 'aadClientSecret' ) {
errors.push(intl.t('validation.required', { key }));
}
}
});
}
} }
if ( get(config, 'services.kubeApi.podSecurityPolicy') && if ( get(config, 'services.kubeApi.podSecurityPolicy') &&
@ -833,18 +893,6 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
const clusterOptErrors = get(this, 'clusterOptErrors') || []; const clusterOptErrors = get(this, 'clusterOptErrors') || [];
if ( get(config, 'cloudProvider.name') === 'azure' ) {
const intl = get(this, 'intl');
Object.keys(AzureInfo).forEach((key) => {
if ( get(AzureInfo, `${ key }.required`) && !get(config, `cloudProvider.azureCloudProvider.${ key }`)) {
if ( this.isNew || this.isEdit && key !== 'aadClientSecret' ) {
errors.push(intl.t('validation.required', { key }));
}
}
});
}
set(this, 'errors', errors); set(this, 'errors', errors);
return errors.length === 0 && clusterOptErrors.length === 0; return errors.length === 0 && clusterOptErrors.length === 0;
@ -922,29 +970,33 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
loadToken() { loadToken() {
const cluster = get(this, 'primaryResource'); const cluster = get(this, 'primaryResource');
setProperties(this, { if (cluster.getOrCreateToken) {
step: 2,
loading: true
});
return cluster.getOrCreateToken().then((token) => {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
setProperties(this, { setProperties(this, {
token, step: 2,
loading: false loading: true
}); });
}).catch((err) => {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
get(this, 'growl').fromError('Error getting command', err); return cluster.getOrCreateToken().then((token) => {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
set(this, 'loading', false); setProperties(this, {
}); token,
loading: false
});
}).catch((err) => {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
get(this, 'growl').fromError('Error getting command', err);
set(this, 'loading', false);
});
} else {
return;
}
}, },
findExcludedKeys(resourceFields) { findExcludedKeys(resourceFields) {
@ -1268,7 +1320,7 @@ export default InputTextFile.extend(ManageLabels, ClusterDriver, {
let path = question.variable; let path = question.variable;
if (!question.variable.includes('uiOverride') && question.default) { if (!question.variable.includes('uiOverride') && question.default) {
set(primaryResource, path, question.default); deepSet(primaryResource, path, question.default);
} }
set(question, 'primaryResource', primaryResource); set(question, 'primaryResource', primaryResource);

View File

@ -33,31 +33,44 @@
<section class="cluster-template-select mb-5"> <section class="cluster-template-select mb-5">
<div class="row"> <div class="row">
{{#if (or (or model.clusterTemplateRevisions model.clusterTemplateRevision) clusterTemplatesEnforced)}} {{#if (or (or model.clusterTemplateRevisions model.clusterTemplateRevision) clusterTemplatesEnforced)}}
<div class="col span-6"> <div>
<label class="acc-label" for="use-existing-cluster-template"> <label class="acc-label" for="use-existing-cluster-template">
{{input {{input
class="input-lg" class="input-lg"
type="checkbox" type="checkbox"
checked=useClusterTemplate checked=useClusterTemplate
id="use-existing-cluster-template" id="use-existing-cluster-template"
disabled=(or clusterTemplatesEnforced pasteOrUpload) disabled=(or isEdit (or clusterTemplatesEnforced pasteOrUpload))
}} }}
{{t "clusterNew.rke.clustersSelectTemplate.label"}} {{t "clusterNew.rke.clustersSelectTemplate.label"}}
</label> </label>
{{#if useClusterTemplate}} </div>
{{#if useClusterTemplate}}
<div class="col span-6">
{{new-select {{new-select
id="input-cluster-template-select" id="input-cluster-template-select"
classNames="form-control" classNames="form-control"
optionValuePath="clusterTemplateRevisionId" optionValuePath="id"
optionLabelPath="clusterTemplateRevisionId" optionLabelPath="name"
optionGroupPath="clusterTemplateName" content=filteredClusterTemplates
content=allTemplates value=selectedClusterTemplateId
value=clusterTemplateRevisionId
prompt=(t "clusterNew.rke.clustersSelectTemplate.select.prompt") prompt=(t "clusterNew.rke.clustersSelectTemplate.select.prompt")
localizedPrompt=true localizedPrompt=true
}} }}
{{/if}} </div>
</div> <div class="col span-6">
{{new-select
classNames="form-control"
optionValuePath="id"
optionLabelPath="name"
content=filteredTemplateRevisions
value=clusterTemplateRevisionId
disabled=(not selectedClusterTemplateId)
prompt=(t "clusterNew.rke.clustersSelectTemplateRevision.select.prompt")
localizedPrompt=true
}}
</div>
{{/if}}
{{/if}} {{/if}}
</div> </div>
</section> </section>

View File

@ -8,6 +8,7 @@ import { alias } from '@ember/object/computed';
import { isEmpty } from '@ember/utils'; import { isEmpty } from '@ember/utils';
import C from 'ui/utils/constants'; import C from 'ui/utils/constants';
import { azure as AzureInfo } from './cloud-provider-info'; import { azure as AzureInfo } from './cloud-provider-info';
import { next } from '@ember/runloop';
const azureDefaults = C.AZURE_DEFAULTS; const azureDefaults = C.AZURE_DEFAULTS;
const GENERIC_PATH = 'cluster.rancherKubernetesEngineConfig.cloudProvider.cloudConfig'; const GENERIC_PATH = 'cluster.rancherKubernetesEngineConfig.cloudProvider.cloudConfig';
@ -110,30 +111,47 @@ export default Component.extend({
'clusterTemplateCreate', 'clusterTemplateCreate',
'applyClusterTemplate', 'applyClusterTemplate',
'clusterTemplateRevision.questions', 'clusterTemplateRevision.questions',
'clusterTemplateRevision.id',
function() { function() {
let { clusterTemplateRevision, applyClusterTemplate } = this; let { clusterTemplateRevision, applyClusterTemplate } = this;
if (applyClusterTemplate && clusterTemplateRevision && clusterTemplateRevision.questions) { if (applyClusterTemplate && clusterTemplateRevision) {
let found = clusterTemplateRevision.questions.filter((ctr) => { if (clusterTemplateRevision.questions) {
return ctr.variable.includes('rancherKubernetesEngineConfig.cloudProvider'); let found = clusterTemplateRevision.questions.filter((ctr) => {
}); return ctr.variable.includes('rancherKubernetesEngineConfig.cloudProvider');
});
return found.length >= 1; if (found.length === 0 && this.selectedCloudProvider !== 'none') {
set(this, 'selectedCloudProvider', 'none');
}
return found.length >= 1;
} else {
if (this.configName) {
next(() => {
set(this, 'selectedCloudProvider', this.configName);
});
}
}
} else {
if (!this.configName) {
next(() => {
set(this, 'selectedCloudProvider', 'none');
});
}
} }
return false; return false;
}), }),
isCreateClusterOrClusterTemplate: computed('', function() { isCreateClusterOrClusterTemplate: computed('applyClusterTemplate', function() {
const { clusterTemplateCreate, applyClusterTemplate } = this; const { applyClusterTemplate } = this;
if (!clusterTemplateCreate && !applyClusterTemplate) { if (applyClusterTemplate) {
return true; return false;
} else if (clusterTemplateCreate) { } else {
return true; return true;
} }
return false;
}), }),
checkDefaults(record) { checkDefaults(record) {

View File

@ -196,7 +196,7 @@ export default Component.extend({
ignoreFields, ignoreFields,
} = this; } = this;
allQuestions = allQuestions.slice(); allQuestions = ( allQuestions || []).slice();
allQuestions.forEach((q) => { allQuestions.forEach((q) => {
if (ignoreFields.includes(q.variable)) { if (ignoreFields.includes(q.variable)) {

View File

@ -6,11 +6,8 @@ import { get, set } from '@ember/object';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed'; import { alias } from '@ember/object/computed';
import Errors from 'ui/utils/errors'; import Errors from 'ui/utils/errors';
import { randomStr } from 'shared/utils/util';
import { reject } from 'rsvp'; import { reject } from 'rsvp';
export default Component.extend(ViewNewEdit, ChildHook, { export default Component.extend(ViewNewEdit, ChildHook, {
globalStore: service(), globalStore: service(),
router: service(), router: service(),
@ -36,12 +33,6 @@ export default Component.extend(ViewNewEdit, ChildHook, {
this._super(...arguments); this._super(...arguments);
set(this, 'originalCluster', get(this, 'clusterTemplateRevision.clusterConfig').clone()); set(this, 'originalCluster', get(this, 'clusterTemplateRevision.clusterConfig').clone());
let { clusterTemplateRevision } = this;
if (!clusterTemplateRevision.name) {
set(clusterTemplateRevision, 'name', `revision-${ randomStr(8, 8, 'loweralpha') }`);
}
}, },
actions: { actions: {

View File

@ -18,6 +18,7 @@ export default Component.extend(ViewNewEdit, ChildHook, {
intl: service(), intl: service(),
access: service(), access: service(),
cookies: service(), cookies: service(),
router: service(),
layout, layout,
step: 1, step: 1,
@ -28,6 +29,7 @@ export default Component.extend(ViewNewEdit, ChildHook, {
reloadingSchema: false, reloadingSchema: false,
schemaReloaded: false, schemaReloaded: false,
applyClusterTemplate: false, applyClusterTemplate: false,
routeLoading: false,
showClassicLauncher: false, showClassicLauncher: false,
nodePoolErrors: null, nodePoolErrors: null,
@ -58,11 +60,26 @@ export default Component.extend(ViewNewEdit, ChildHook, {
if ( isEmpty(get(this, 'cluster.id')) ){ if ( isEmpty(get(this, 'cluster.id')) ){
set(this, 'newCluster', true); set(this, 'newCluster', true);
} }
this.router.on('routeWillChange', (/* transition */) => {
if ( !this.isDestroyed || !this.isDestroying ) {
set(this, 'routeLoading', true);
}
});
this.router.on('routeDidChange', (/* transition */) => {
if ( !this.isDestroyed || !this.isDestroying ) {
set(this, 'routeLoading', false);
}
});
}, },
actions: { actions: {
updateFromYaml(newOpts) { updateFromYaml(newOpts) {
this.cluster.replaceWith(newOpts); if (this.isEdit) {
this.cluster.merge(newOpts);
} else {
this.cluster.replaceWith(newOpts);
}
}, },
clickNext() { clickNext() {

View File

@ -82,22 +82,24 @@
{{/accordion-list}} {{/accordion-list}}
{{/if}} {{/if}}
{{component driverInfo.driverComponent {{#unless routeLoading}}
applyClusterTemplate=applyClusterTemplate {{component driverInfo.driverComponent
clusterTemplateQuestions=model.clusterTemplateRevision.questions applyClusterTemplate=applyClusterTemplate
clusterTemplateRevisionId=clusterTemplateRevisionId clusterTemplateQuestions=model.clusterTemplateRevision.questions
clusterErrors=errors clusterTemplateRevisionId=clusterTemplateRevisionId
mode=mode clusterErrors=errors
model=model mode=mode
nodePoolErrors=nodePoolErrors model=model
nodeWhich=driverInfo.nodeWhich nodePoolErrors=nodePoolErrors
originalCluster=originalCluster nodeWhich=driverInfo.nodeWhich
otherErrors=memberErrors originalCluster=originalCluster
save=(action "save") otherErrors=memberErrors
close=(action "close") save=(action "save")
registerHook=(action "registerHook") close=(action "close")
updateFromYaml=(action "updateFromYaml") registerHook=(action "registerHook")
}} updateFromYaml=(action "updateFromYaml")
}}
{{/unless}}
{{#if (and isEdit (not provider))}} {{#if (and isEdit (not provider))}}
{{top-errors errors=errors}} {{top-errors errors=errors}}

View File

@ -54,7 +54,6 @@ export default Component.extend({
initialVersion, initialVersion,
defaultK8sVersion, defaultK8sVersion,
applyClusterTemplate = false, applyClusterTemplate = false,
clusterTemplateCreate = false,
clusterTemplateQuestions = [], clusterTemplateQuestions = [],
} = this; } = this;
@ -70,7 +69,7 @@ export default Component.extend({
let maxVersion = maxSatisfying(versions, defaultK8sVersionRange); let maxVersion = maxSatisfying(versions, defaultK8sVersionRange);
if (applyClusterTemplate || clusterTemplateCreate) { if ( applyClusterTemplate ) {
var overrideMatch = ( clusterTemplateQuestions || [] ).findBy('variable', 'rancherKubernetesEngineConfig.kubernetesVersion'); var overrideMatch = ( clusterTemplateQuestions || [] ).findBy('variable', 'rancherKubernetesEngineConfig.kubernetesVersion');
if (overrideMatch) { if (overrideMatch) {
@ -78,7 +77,10 @@ export default Component.extend({
// the template creator lets them override this but the initial version is a dot x so we should choose the biggest version in the .x range // the template creator lets them override this but the initial version is a dot x so we should choose the biggest version in the .x range
maxVersion = maxSatisfying(versions, initialVersion); maxVersion = maxSatisfying(versions, initialVersion);
} else { } else {
supportedVersionsRange = overrideMatch.satisfies; if (overrideMatch.satisfies) {
supportedVersionsRange = overrideMatch.satisfies;
}
maxVersion = maxSatisfying(versions, supportedVersionsRange); maxVersion = maxSatisfying(versions, supportedVersionsRange);
} }
} }

View File

@ -69,6 +69,10 @@ export default Mixin.create({
cb(true); cb(true);
}) })
.catch((err) => { .catch((err) => {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.send('error', err); this.send('error', err);
this.errorSaving(err); this.errorSaving(err);
cb(false); cb(false);

View File

@ -61,6 +61,7 @@
"ember-concurrency": "^0.8.24", "ember-concurrency": "^0.8.24",
"ember-copy": "^1.0.0", "ember-copy": "^1.0.0",
"ember-credit-card": "^2.4.0", "ember-credit-card": "^2.4.0",
"ember-deep-set": "^0.2.0",
"ember-drag-drop": "^0.4.7", "ember-drag-drop": "^0.4.7",
"ember-engines": "^0.6.1", "ember-engines": "^0.6.1",
"ember-export-application-global": "^2.0.0", "ember-export-application-global": "^2.0.0",

View File

@ -3190,10 +3190,13 @@ clusterNew:
label: EIP Share Type label: EIP Share Type
rke: rke:
clustersSelectTemplate: clustersSelectTemplate:
label: "Use an existing cluster template" label: "Use an existing cluster template and revision"
select: select:
label: Cluster Templates label: Cluster Templates
prompt: Select a cluster template prompt: Select a cluster template
clustersSelectTemplateRevision:
select:
prompt: Select a cluster template revision
etcd: etcd:
enabled: enabled:
label: Recurring etcd Snapshot Enabled label: Recurring etcd Snapshot Enabled

View File

@ -4641,6 +4641,13 @@ ember-credit-card@^2.4.0:
ember-cli-htmlbars "2.0.3" ember-cli-htmlbars "2.0.3"
ember-model-validator "^2.18.0" ember-model-validator "^2.18.0"
ember-deep-set@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/ember-deep-set/-/ember-deep-set-0.2.0.tgz#93428b599f884c3da0550cbcc062b9ec5969a71e"
integrity sha512-3vg9Cw4CIInXzufZMQmScClg23mUw+2ybO53L51spFYP/eGaVmGduWmhrVljyl4lHKN7hW/jvG/YVWtwTPSTKA==
dependencies:
ember-cli-babel "^7.1.2"
ember-diff-attrs@^0.2.1: ember-diff-attrs@^0.2.1:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/ember-diff-attrs/-/ember-diff-attrs-0.2.2.tgz#57baf6907957de004d9aff947809dfe78a054b3b" resolved "https://registry.yarnpkg.com/ember-diff-attrs/-/ember-diff-attrs-0.2.2.tgz#57baf6907957de004d9aff947809dfe78a054b3b"