mirror of https://github.com/rancher/ui.git
Merge pull request #1890 from loganhz/aliyun
Update Aliyun ECS node driver UI
This commit is contained in:
commit
57448c5b9c
|
|
@ -22,6 +22,7 @@ module.exports = {
|
|||
"Ui": true,
|
||||
"async": true,
|
||||
"AWS": true,
|
||||
"ALY": true,
|
||||
"Identicon": true,
|
||||
"md5": true,
|
||||
"_": true,
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ module.exports = function(defaults) {
|
|||
app.import('vendor/prompt/prompt-v1-latin-600.woff', { destDir: 'assets/fonts/'});
|
||||
app.import('vendor/prompt/prompt-v1-latin-600.woff2',{ destDir: 'assets/fonts/'});
|
||||
app.import('vendor/aws-sdk-ec2.js');
|
||||
app.import('vendor/aliyun-sdk.js');
|
||||
app.import('vendor/file-saver/fileSaver.mini.js');
|
||||
app.import('vendor/json-sanitizer/json-sanitizer.js');
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ module.exports = {
|
|||
"Ui": true,
|
||||
"async": true,
|
||||
"AWS": true,
|
||||
"ALY": true,
|
||||
"Identicon": true,
|
||||
"md5": true,
|
||||
"_": true,
|
||||
|
|
|
|||
|
|
@ -1,41 +1,331 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import { set, get, observer, setProperties, computed } from '@ember/object';
|
||||
import Component from '@ember/component';
|
||||
import NodeDriver from 'shared/mixins/node-driver';
|
||||
import layout from './template';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { Promise as EmberPromise } from 'rsvp';
|
||||
|
||||
let ioOptimized=[
|
||||
{
|
||||
value : "none",
|
||||
const ENDPOINT = 'https://ecs.aliyuncs.com';
|
||||
const PAGE_SIZE = 50;
|
||||
const NONE_OPT_DISK = [{
|
||||
value: 'cloud'
|
||||
}];
|
||||
|
||||
const OPT_DISK = [{
|
||||
value: 'cloud_efficiency'
|
||||
},
|
||||
{
|
||||
value: "optimized",
|
||||
},
|
||||
value: 'cloud_ssd'
|
||||
}
|
||||
];
|
||||
|
||||
export default Component.extend(NodeDriver, {
|
||||
layout,
|
||||
|
||||
intl: service(),
|
||||
settings: service(),
|
||||
|
||||
driverName: 'aliyunecs',
|
||||
config: alias('model.aliyunecsConfig'),
|
||||
ioOptimized: ioOptimized,
|
||||
|
||||
zones: null,
|
||||
regions: null,
|
||||
securityGroups: null,
|
||||
images: null,
|
||||
instanceTypes: null,
|
||||
|
||||
ecsClient: null,
|
||||
step: 1,
|
||||
|
||||
bootstrap: function () {
|
||||
let config = this.get('globalStore').createRecord({
|
||||
const config = get(this, 'globalStore').createRecord({
|
||||
type: 'aliyunecsConfig',
|
||||
accessKeySecret: ''
|
||||
accessKeySecret: '',
|
||||
ioOptimized: 'optimized',
|
||||
});
|
||||
|
||||
this.set('model.aliyunecsConfig', config);
|
||||
set(this, 'model.aliyunecsConfig', config);
|
||||
set(this, 'model.engineRegistryMirror', ['https://s06nkgus.mirror.aliyuncs.com']);
|
||||
set(this, 'model.engineInstallURL', 'http://dev-tool.oss-cn-shenzhen.aliyuncs.com/docker-install/1.13.1.sh');
|
||||
},
|
||||
validate() {
|
||||
let errors = [];
|
||||
|
||||
if ( !this.get('model.name') ) {
|
||||
actions: {
|
||||
alyLogin: function (cb) {
|
||||
setProperties(this, {
|
||||
'errors': null,
|
||||
'config.accessKeyId': (get(this, 'config.accessKeyId') || '').trim(),
|
||||
'config.accessKeySecret': (get(this, 'config.accessKeySecret') || '').trim(),
|
||||
});
|
||||
|
||||
const errors = get(this, 'errors') || [];
|
||||
const intl = get(this, 'intl');
|
||||
|
||||
const accessKey = get(this, 'config.accessKeyId');
|
||||
const accessSecret = get(this, 'config.accessKeySecret');
|
||||
|
||||
if (!accessKey) {
|
||||
errors.push(intl.t('nodeDriver.aliyunecs.errors.accessKeyRequired'));
|
||||
}
|
||||
|
||||
if (!accessSecret) {
|
||||
errors.push(intl.t('nodeDriver.aliyunecs.errors.accessSecretRequired'));
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
let ecs;
|
||||
|
||||
try {
|
||||
const location = window.location;
|
||||
let endpoint = get(this, 'config.apiEndpoint') ? get(this, 'config.apiEndpoint') : ENDPOINT;
|
||||
endpoint = get(this,'app.proxyEndpoint') + '/' + endpoint.replace('//', '/');
|
||||
endpoint = `${location.protocol}//${window.location.host}${endpoint}`;
|
||||
|
||||
ecs = new ALY.ECS({
|
||||
accessKeyId: get(this, 'config.accessKeyId'),
|
||||
secretAccessKey: get(this, 'config.accessKeySecret'),
|
||||
apiVersion: '2014-05-26',
|
||||
endpoint,
|
||||
});
|
||||
|
||||
ecs.describeRegions({}, (err, res) => {
|
||||
if (err) {
|
||||
let errors = get(this, 'errors') || [];
|
||||
errors.pushObject(err.message || err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
set(this, 'ecsClient', ecs);
|
||||
set(this, 'regions', res.Regions.Region.map((region) => {
|
||||
return {
|
||||
value: region.RegionId,
|
||||
label: region.LocalName,
|
||||
};
|
||||
}));
|
||||
this.regionDidChange();
|
||||
set(this, 'step', 2);
|
||||
cb();
|
||||
});
|
||||
} catch (err) {
|
||||
const errors = get(this, 'errors') || [];
|
||||
errors.pushObject(err.message || err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
loadStorageTypes: function (cb) {
|
||||
if (!get(this, 'config.securityGroup')) {
|
||||
set(this, 'config.securityGroup', 'docker-machine')
|
||||
}
|
||||
set(this, 'step', 3);
|
||||
this.diskCategoryChoicesDidChange();
|
||||
cb();
|
||||
},
|
||||
|
||||
loadInstanceTypes: function (cb) {
|
||||
this.fetch('Image', 'Images')
|
||||
.then((images) => {
|
||||
set(this, 'images', images.filter((image) => image.raw.OSType === 'linux'));
|
||||
set(this, 'config.imageId', get(this, 'images.firstObject.value'));
|
||||
this.fetch('InstanceType', 'InstanceTypes')
|
||||
.then((instanceTypes) => {
|
||||
set(this, 'instanceTypes', instanceTypes.map((instanceType) => {
|
||||
return {
|
||||
group: instanceType.raw.InstanceTypeFamily,
|
||||
value: instanceType.value,
|
||||
label: `${instanceType.raw.InstanceTypeId} ( ${instanceType.raw.CpuCoreCount} ${instanceType.raw.CpuCoreCount > 1 ? 'Cores': 'Core'} ${instanceType.raw.MemorySize}GB RAM )`,
|
||||
}
|
||||
}));
|
||||
set(this, 'config.instanceType', get(this, 'instanceTypes.firstObject.value'))
|
||||
set(this, 'step', 4);
|
||||
cb();
|
||||
})
|
||||
.catch((err) => {
|
||||
const errors = get(this, 'errors') || [];
|
||||
errors.pushObject(err.message || err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
return;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
const errors = get(this, 'errors') || [];
|
||||
errors.pushObject(err.message || err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
return;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
vpcDidChange: observer('config.vpcId', function () {
|
||||
const vpcId = get(this, 'config.vpcId');
|
||||
if (vpcId) {
|
||||
this.fetch('VSwitch', 'VSwitches').then((vswitches) => {
|
||||
set(this, 'vswitches', vswitches);
|
||||
const selectedVSwitch = get(this, 'config.vswitchId');
|
||||
if (selectedVSwitch) {
|
||||
const found = vswitches.findBy('VSwitchId', selectedVSwitch);
|
||||
if (!found) {
|
||||
set(this, 'config.vswitchId', null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.fetch('SecurityGroup', 'SecurityGroups').then((securityGroups) => {
|
||||
set(this, 'securityGroups', securityGroups);
|
||||
const selectedSecurityGroup = get(this, 'config.securityGroup');
|
||||
if (selectedSecurityGroup) {
|
||||
const found = securityGroups.findBy('SecurityGroupId', selectedSecurityGroup);
|
||||
if (!found) {
|
||||
set(this, 'config.securityGroup', 'docker-machine');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
set(this, 'config.vswitchId', null);
|
||||
set(this, 'config.securityGroup', 'docker-machine');
|
||||
}
|
||||
}),
|
||||
|
||||
regionDidChange: observer('config.region', function () {
|
||||
const region = get(this, 'config.region');
|
||||
if (region) {
|
||||
this.fetch('Vpc', 'Vpcs').then((vpcs) => {
|
||||
set(this, 'vpcs', vpcs);
|
||||
const selectedVPC = get(this, 'config.vpcId');
|
||||
if (selectedVPC) {
|
||||
const found = vpcs.findBy('VpcId', selectedVPC);
|
||||
if (!found) {
|
||||
set(this, 'config.vpcId', null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.fetch('Zone', 'Zones').then((zones) => {
|
||||
set(this, 'zones', zones);
|
||||
const selectedZone = get(this, 'config.zone');
|
||||
if (selectedZone) {
|
||||
const found = zones.findBy('ZoneId', selectedZone);
|
||||
if (!found) {
|
||||
set(this, 'config.zone', null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
diskCategoryChoices: computed('config.ioOptimized', function () {
|
||||
return get(this, 'config.ioOptimized') === 'none' ? NONE_OPT_DISK : OPT_DISK;
|
||||
}),
|
||||
|
||||
diskCategoryChoicesDidChange: observer('diskCategoryChoices.@each.value', function () {
|
||||
set(this, 'config.systemDiskCategory', get(this, 'diskCategoryChoices.firstObject.value'));
|
||||
set(this, 'config.diskCategory', get(this, 'diskCategoryChoices.firstObject.value'));
|
||||
}),
|
||||
|
||||
validate: function () {
|
||||
this._super();
|
||||
const errors = get(this, 'model').validationErrors();
|
||||
|
||||
const intl = get(this, 'intl');
|
||||
|
||||
const name = get(this, 'model.name');
|
||||
|
||||
const sshPassword = get(this, 'config.sshPassword');
|
||||
|
||||
const lower = /[a-z]/.test(sshPassword) ? 1 : 0;
|
||||
const upper = /[A-Z]/.test(sshPassword) ? 1 : 0;
|
||||
const number = /[0-9]/.test(sshPassword) ? 1 : 0;
|
||||
const special = /[?+*$^().|<>';:\-=\[\]\{\},&%#@!~`\\]/.test(sshPassword) ? 1 : 0;
|
||||
|
||||
if (!name) {
|
||||
errors.push('Name is required');
|
||||
}
|
||||
|
||||
this.set('errors', errors);
|
||||
if (sshPassword && (sshPassword.length < 8) || sshPassword.length > 30) {
|
||||
errors.push(intl.t('nodeDriver.aliyunecs.errors.sshPasswordLengthNotValid'));
|
||||
}
|
||||
|
||||
if (sshPassword && !/[?+*$^().|<>';:\-=\[\]\{\},&%#@!~`\\a-zA-Z0-9]+/.test(sshPassword)) {
|
||||
errors.push(intl.t('nodeDriver.aliyunecs.errors.sshPasswordInvalidCharacter'));
|
||||
}
|
||||
|
||||
if (sshPassword && (lower + upper + number + special < 3)) {
|
||||
errors.push(get(this, 'intl').t('nodeDriver.aliyunecs.errors.sshPasswordFormatError'));
|
||||
}
|
||||
|
||||
set(this, 'errors', errors);
|
||||
return errors.length === 0;
|
||||
},
|
||||
|
||||
fetch: function (resource, plural, page = 1) {
|
||||
const ecs = get(this, 'ecsClient');
|
||||
const region = get(this, 'config.region');
|
||||
const results = [];
|
||||
let params = {
|
||||
PageSize: PAGE_SIZE,
|
||||
PageNumber: page,
|
||||
};
|
||||
|
||||
switch (resource) {
|
||||
case 'InstanceType':
|
||||
params = {};
|
||||
break;
|
||||
case 'VSwitch':
|
||||
params.VpcId = get(this, 'config.vpcId');
|
||||
break;
|
||||
case 'SecurityGroup':
|
||||
params.VpcId = get(this, 'config.vpcId');
|
||||
params.RegionId = region;
|
||||
break;
|
||||
case 'Zone':
|
||||
params = {
|
||||
RegionId: region,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
params.RegionId = region;
|
||||
}
|
||||
|
||||
return new EmberPromise((resolve, reject) => {
|
||||
ecs[`describe${plural}`](params, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const current = res[`${plural}`][resource];
|
||||
results.pushObjects(current.map((item) => {
|
||||
return {
|
||||
label: item[`${resource}Id`],
|
||||
value: item[`${resource}Id`],
|
||||
raw: item,
|
||||
};
|
||||
}));
|
||||
|
||||
if (res.TotalCount > ((PAGE_SIZE * (page - 1)) + current.length)) {
|
||||
return this.fetch(resource, plural, page + 1)
|
||||
.then((array) => {
|
||||
results.pushObjects(array);
|
||||
resolve(results);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
resolve(results);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,260 +1,270 @@
|
|||
<section class="horizontal-form">
|
||||
<div class="container-fluid">
|
||||
{{#if showNameScale}}
|
||||
<div class="box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.instanceSection'}}</h4>
|
||||
<div class="row mb-20">
|
||||
{{#accordion-list showExpandAll=false as | al expandFn |}}
|
||||
<div class="over-hr"><span>{{driverOptionsTitle}}</span></div>
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.aliyunecs.accountSection.label')
|
||||
detail=(t 'nodeDriver.aliyunecs.accountSection.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-11-of-23 mt-0 mb-0">
|
||||
{{form-name-description
|
||||
name=prefix
|
||||
nameRequired=true
|
||||
namePlaceholder="hostsPage.new.name.placeholder"
|
||||
nameHelpText=nameCountLabel
|
||||
descriptionShown=true
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.accessKey.label'}}{{field-required}}</label>
|
||||
{{#input-or-display editable=(eq step 1) value=config.accessKeyId}}
|
||||
{{input type="text" class="form-control" value=config.accessKeyId placeholder=(t 'nodeDriver.aliyunecs.accessKey.placeholder')}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.accessKeySecret.label'}}{{field-required}}</label>
|
||||
{{#if (eq step 1)}}
|
||||
{{input type="password" class="form-control" value=config.accessKeySecret placeholder=(t 'nodeDriver.aliyunecs.accessKeySecret.placeholder')}}
|
||||
{{else}}
|
||||
<div class="text-muted text-italic">{{t 'nodeDriver.aliyunecs.accessKeySecret.provided'}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.apiEndpoint.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 1) value=config.apiEndpoint}}
|
||||
{{input type="text" class="form-control" value=config.apiEndpoint placeholder=(t 'nodeDriver.aliyunecs.apiEndpoint.placeholder')}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#if (eq step 1)}}
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel
|
||||
save="alyLogin"
|
||||
cancel="cancel"
|
||||
createLabel="nodeDriver.aliyunecs.accountSection.next"
|
||||
savingLabel="nodeDriver.aliyunecs.accountSection.loading"
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-11-of-23 mt-0 mb-0 offset-1-of-23">
|
||||
{{form-count
|
||||
min=0
|
||||
initialScale=1
|
||||
setScale=(action (mut count))
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="row box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.accountSection'}}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.accessKey.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.accessKeyId placeholder=(t 'nodeDriver.aliyunecs.accessKey.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.accessKeySecret.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="password" class="form-control" value=config.accessKeySecret placeholder=(t 'nodeDriver.aliyunecs.accessKeySecret.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.apiEndpoint.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.apiEndpoint placeholder=(t 'nodeDriver.aliyunecs.apiEndpoint.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.instanceOptionsSection'}}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.instanceDescription.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.description placeholder=(t 'nodeDriver.aliyunecs.instanceDescription.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.instanceType.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.instanceType placeholder=(t 'nodeDriver.aliyunecs.instanceType.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.systemImage.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.imageId placeholder=(t 'nodeDriver.aliyunecs.systemImage.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.instanceTag.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.tag placeholder=(t 'nodeDriver.aliyunecs.instanceTag.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.internetMaxBandwidth.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="input-group">
|
||||
{{input type="text" class="form-control" value=config.internetMaxBandwidth placeholder=(t 'nodeDriver.aliyunecs.internetMaxBandwidth.placeholder')}}
|
||||
<div class="input-group-addon bg-default">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.aliyunSLB.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.slbId placeholder=(t 'nodeDriver.aliyunecs.aliyunSLB.placeholder')}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.storageSection'}}</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.ioOptimized.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{!--{{input type="text" class="form-control" value=config.ioOptimized placeholder=(t 'nodeDriver.aliyunecs.ioOptimized.placeholder')}}--}}
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=ioOptimized
|
||||
optionLabelPath='value'
|
||||
value=config.ioOptimized
|
||||
<div class="{{unless (gte step 2) 'hide'}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.aliyunecs.networkSection.label')
|
||||
detail=(t 'nodeDriver.aliyunecs.networkSection.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.region.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.region}}
|
||||
{{new-select classNames="form-control" content=regions value=config.region}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.systemDiskCategory.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.systemDiskCategory placeholder=(t 'nodeDriver.aliyunecs.systemDiskCategory.placeholder')}}
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.vpcId.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.vpcId}}
|
||||
{{new-select classNames="form-control" content=vpcs value=config.vpcId prompt="nodeDriver.aliyunecs.vpcId.prompt" localizedPrompt=true}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.dataDiskCategory.label'}}</label>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.securityGroup.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.securityGroup}}
|
||||
{{new-select classNames="form-control" content=securityGroups value=config.securityGroup prompt="nodeDriver.aliyunecs.securityGroup.prompt" localizedPrompt=true}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.vswitchId.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.vswitchId}}
|
||||
{{new-select classNames="form-control" content=vswitches value=config.vswitchId prompt="nodeDriver.aliyunecs.vswitchId.prompt" localizedPrompt=true}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.diskCategory placeholder=(t 'nodeDriver.aliyunecs.dataDiskCategory.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.dataDiskSize.label'}}</label>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.zone.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.zone}}
|
||||
{{new-select classNames="form-control" content=zones value=config.zone prompt="nodeDriver.aliyunecs.zone.prompt" localizedPrompt=true}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.routeCIDR.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.routeCidr}}
|
||||
{{input type="text" class="form-control" value=config.routeCidr placeholder=(t 'nodeDriver.aliyunecs.routeCIDR.placeholder')}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.privateIp.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.privateIp}}
|
||||
{{input type="text" class="form-control" value=config.privateIp placeholder=(t 'nodeDriver.aliyunecs.privateIp.placeholder')}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.privateAddressOnly.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 2) value=config.privateAddressOnly}}
|
||||
<div>
|
||||
{{input type="checkbox" class="form-control" checked=config.privateAddressOnly}}
|
||||
</div>
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#if (eq step 2)}}
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel
|
||||
save="loadStorageTypes"
|
||||
cancel="cancel"
|
||||
createLabel="nodeDriver.aliyunecs.networkSection.next"
|
||||
savingLabel="nodeDriver.aliyunecs.networkSection.loading"
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="{{unless (gte step 3) 'hide'}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.aliyunecs.storageSection.label')
|
||||
detail=(t 'nodeDriver.aliyunecs.storageSection.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.ioOptimized.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 3) value=config.ioOptimized}}
|
||||
<div>
|
||||
<label class="mr-20 hand">
|
||||
{{radio-button selection=config.ioOptimized value='optimized'}} {{t 'nodeDriver.aliyunecs.ioOptimized.optimized'}}
|
||||
</label>
|
||||
<label class="hand">
|
||||
{{radio-button selection=config.ioOptimized value='none'}} {{t 'nodeDriver.aliyunecs.ioOptimized.none'}}
|
||||
</label>
|
||||
</div>
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.systemDiskCategory.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 3) value=config.systemDiskCategory}}
|
||||
{{new-select classNames="form-control" content=diskCategoryChoices optionLabelPath='value' value=config.systemDiskCategory}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.dataDiskCategory.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 3) value=config.diskCategory}}
|
||||
{{new-select classNames="form-control" content=diskCategoryChoices optionLabelPath='value' value=config.diskCategory}}
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.dataDiskSize.label'}}</label>
|
||||
{{#input-or-display editable=(eq step 3) value=config.diskSize}}
|
||||
<div class="input-group">
|
||||
{{input type="text" class="form-control" value=config.diskSize placeholder=(t 'nodeDriver.aliyunecs.dataDiskSize.placeholder')}}
|
||||
<div class="input-group-addon bg-default">GB</div>
|
||||
</div>
|
||||
{{/input-or-display}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#if (eq step 3)}}
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel
|
||||
save="loadInstanceTypes"
|
||||
cancel="cancel"
|
||||
createLabel="nodeDriver.aliyunecs.storageSection.next"
|
||||
savingLabel="nodeDriver.aliyunecs.storageSection.loading"
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="{{unless (gte step 4) 'hide'}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.aliyunecs.instanceOptionsSection.label')
|
||||
detail=(t 'nodeDriver.aliyunecs.instanceOptionsSection.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.instanceDescription.label'}}</label>
|
||||
{{input type="text" class="form-control" value=config.description placeholder=(t 'nodeDriver.aliyunecs.instanceDescription.placeholder')}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.instanceType.label'}}</label>
|
||||
{{new-select classNames="form-control" content=instanceTypes value=config.instanceType}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.region.label'}}</label>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.systemImage.label'}}</label>
|
||||
{{new-select classNames="form-control" content=images optionLabelPath='raw.OSName' optionValuePath='value' value=config.imageId}}
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.region placeholder=(t 'nodeDriver.aliyunecs.region.placeholder')}}
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.internetMaxBandwidth.label'}}</label>
|
||||
<div class="input-group">
|
||||
{{input-integer min=1 max=100 class="form-control" value=config.internetMaxBandwidth placeholder=(t 'nodeDriver.aliyunecs.internetMaxBandwidth.placeholder')}}
|
||||
<div class="input-group-addon bg-default">Mbps</div>
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.zone.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.zone placeholder=(t 'nodeDriver.aliyunecs.zone.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.networkSection'}}</h4>
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.routeCIDR.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.routeCidr placeholder=(t 'nodeDriver.aliyunecs.routeCIDR.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.vpcId.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.vpcId placeholder=(t 'nodeDriver.aliyunecs.vpcId.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.vswitchId.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.vswitchId placeholder=(t 'nodeDriver.aliyunecs.vswitchId.placeholder')}}
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.aliyunSLB.label'}}</label>
|
||||
{{input type="text" class="form-control" value=config.slbId placeholder=(t 'nodeDriver.aliyunecs.aliyunSLB.placeholder')}}
|
||||
</div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.privateIp.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.privateIp placeholder=(t 'nodeDriver.aliyunecs.privateIp.placeholder')}}
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.aliyunecs.sshPassword.label'}}</label>
|
||||
{{input type="password" class="form-control" value=config.sshPassword placeholder=(t 'nodeDriver.aliyunecs.sshPassword.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.privateAddressOnly.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="checkbox" class="form-control" checked=config.privateAddressOnly}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
{{form-value-array
|
||||
initialValues=config.tag
|
||||
addActionLabel='nodeDriver.aliyunecs.tags.addActionLabel'
|
||||
valueLabel='nodeDriver.aliyunecs.tags.valueLabel'
|
||||
valuePlaceholder='nodeDriver.aliyunecs.tags.placeholder'
|
||||
changed=(action (mut config.tag))
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
<div class="row box mt-20">
|
||||
<h4>{{t 'nodeDriver.aliyunecs.securitySection'}}</h4>
|
||||
<div class="row">
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.securityGroup.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.securityGroup placeholder=(t 'nodeDriver.aliyunecs.securityGroup.placeholder')}}
|
||||
</div>
|
||||
<div class="over-hr"><span>{{templateOptionsTitle}}</span></div>
|
||||
|
||||
<div class="col span-2 col-inline">
|
||||
<label>{{t 'nodeDriver.aliyunecs.sshPassword.label'}}</label>
|
||||
</div>
|
||||
<div class="col span-4">
|
||||
{{input type="text" class="form-control" value=config.sshPassword placeholder=(t 'nodeDriver.aliyunecs.sshPassword.placeholder')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{form-name-description
|
||||
model=model
|
||||
nameRequired=true
|
||||
}}
|
||||
|
||||
<div class="over-hr mt-40 mb-30">
|
||||
<span>{{settings.appName}}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
{{form-user-labels initialLabels=labelResource.labels setLabels=(action 'setLabels') expandAll=null}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#advanced-section}}
|
||||
{{form-engine-opts machine=model showEngineUrl=showEngineUrl}}
|
||||
{{/advanced-section}}
|
||||
</div>
|
||||
{{form-user-labels
|
||||
initialLabels=labelResource.labels
|
||||
setLabels=(action 'setLabels')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
}}
|
||||
|
||||
{{form-engine-opts
|
||||
machine=model
|
||||
showEngineUrl=showEngineUrl
|
||||
}}
|
||||
|
||||
{{top-errors errors=errors}}
|
||||
|
||||
|
||||
{{save-cancel save="save" cancel="cancel" editing=editing}}
|
||||
</section>
|
||||
</div>
|
||||
{{/accordion-list}}
|
||||
|
|
@ -4725,18 +4725,24 @@ nodeDriver:
|
|||
region:
|
||||
label: Region
|
||||
aliyunecs:
|
||||
accountSection: Account Access Section
|
||||
accountSection:
|
||||
label: 1. Account Access
|
||||
detail: API Keys will be used to launch Aliyun ECS Instances.
|
||||
next: "Next: Authenticate & Config network options"
|
||||
loading: Loading Regions from Aliyun ECS...
|
||||
accessKey:
|
||||
label: Access Key*
|
||||
label: Access Key
|
||||
placeholder: Your Aliyun Account Access Key
|
||||
accessKeySecret:
|
||||
label: Access Key Secret*
|
||||
placeholder: Your Key's secret
|
||||
label: Access Key Secret
|
||||
placeholder: Your Aliyun Account Access Key Secret
|
||||
provided: Provided
|
||||
apiEndpoint:
|
||||
label: Api Endpoint
|
||||
placeholder: Private Aliyun Api Server Endpoint
|
||||
instanceSection: Instance Section
|
||||
instanceOptionsSection: Instance Options Section
|
||||
label: API Endpoint
|
||||
placeholder: Private Aliyun API Server Endpoint
|
||||
instanceOptionsSection:
|
||||
label: Instance
|
||||
detail: Customize the Aliyun ECS Instance that will be created.
|
||||
instanceDescription:
|
||||
label: Instance Description
|
||||
placeholder: Instance Description
|
||||
|
|
@ -4746,25 +4752,25 @@ nodeDriver:
|
|||
systemImage:
|
||||
label: System image
|
||||
placeholder: System image
|
||||
instanceTag:
|
||||
label: Instance Tag
|
||||
placeholder: Your Instance Tag in Aliyun
|
||||
internetMaxBandwidth:
|
||||
label: Internet Max Bandwidth
|
||||
placeholder: 1 to 100
|
||||
aliyunSLB:
|
||||
label: Aliyun SLB ID
|
||||
placeholder: Aliyun SLB ID
|
||||
storageSection: Storage Info
|
||||
storageSection:
|
||||
label: Storage
|
||||
detail: Configure the storage for the instances that will be created by this template.
|
||||
next: "Next: Config Aliyun ECS Instance options"
|
||||
loading: Loading Instance Types and Images from Aliyun ECS...
|
||||
ioOptimized:
|
||||
label: Instance Storage I/O Optimized
|
||||
placeholder: none or optimized
|
||||
optimized: Optimized
|
||||
none: None
|
||||
systemDiskCategory:
|
||||
label: System Disk Category
|
||||
placeholder: When Storage is optimized, you can input cloud_efficiency, cloud_ssd or ephemeral_ssd.
|
||||
dataDiskCategory:
|
||||
label: Data Disk Category
|
||||
placeholder: When Storage is optimized, you can input cloud_efficiency, cloud_ssd or ephemeral_ssd.
|
||||
dataDiskSize:
|
||||
label: Data Disk Size
|
||||
placeholder: Disk Size
|
||||
|
|
@ -4773,29 +4779,48 @@ nodeDriver:
|
|||
placeholder: Region
|
||||
zone:
|
||||
label: Available Zone
|
||||
placeholder: Blank for auto select
|
||||
networkSection: Network Section
|
||||
prompt: Choose a Available Zone...
|
||||
networkSection:
|
||||
label: Network
|
||||
detail: Configure the network for the instances that will be created by this template.
|
||||
next: "Next: Config Storage Options"
|
||||
loading: Loading Storage Types from Aliyun ECS...
|
||||
routeCIDR:
|
||||
label: Route CIDR
|
||||
placeholder: e.g. 192.168.1.0/24
|
||||
vpcId:
|
||||
label: Aliyun VPC ID
|
||||
placeholder: Aliyun VPC ID
|
||||
label: VPC
|
||||
prompt: Choose a VPC...
|
||||
vswitchId:
|
||||
label: Aliyun Vswitch ID
|
||||
placeholder: Aliyun Vswitch ID
|
||||
label: VSwitch
|
||||
prompt: Choose a VSwitch...
|
||||
privateIp:
|
||||
label: Private IP
|
||||
placeholder: Private IP in Private Network
|
||||
privateAddressOnly:
|
||||
label: Private Address Only
|
||||
securitySection: Security Section
|
||||
securitySection:
|
||||
label: Security
|
||||
detail: Choose the security groups that will be applied to Instances
|
||||
securityGroup:
|
||||
label: Security Group
|
||||
placeholder: Security Group
|
||||
prompt: Choose a Security Group...
|
||||
sshPassword:
|
||||
label: SSH Password
|
||||
placeholder: Set Instance SSH Password, Blank for Auto set
|
||||
provided: Provided
|
||||
tags:
|
||||
addActionLabel: Add Instance Tag
|
||||
valueLabel: Tags
|
||||
placeholder: e.g. dev
|
||||
errors:
|
||||
accessKeyRequired: Access Key is required.
|
||||
accessSecretRequired: Access Secret Key is required.
|
||||
sshPasswordLengthNotValid: The length of SSH password must between eight and thirty.
|
||||
sshPasswordInvalidCharacter: SSH password contains invalid characters.
|
||||
sshPasswordFormatError: "SSH password must contain at least three out of four kinds of following characters: uppercase letter, lowercase letters, numbers, and special characters."
|
||||
nameNotValidForApp: The name is invalid according to the {appName} hostname rule.
|
||||
zstack:
|
||||
access:
|
||||
title: 1. Account Access
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue