Merge pull request #1205 from westlywright/concloud

New Host Templates and Host Launch
This commit is contained in:
Vincent Fiduccia 2017-06-02 00:07:06 -07:00 committed by GitHub
commit 1b07479e91
55 changed files with 972 additions and 887 deletions

View File

@ -41,7 +41,7 @@
{{else}}
<section>
<div>
{{host-settings saved="savedHost"}}
{{host-settings saved=(action savedHost)}}
</div>
</section>
{{/if}}

View File

@ -2,56 +2,24 @@ import Ember from 'ember';
import Driver from 'ui/mixins/driver';
export default Ember.Component.extend(Driver, {
errors: null,
model: null,
config: null,
hostTemplates: null,
selectedHostTemplate: null,
errors: null,
host: null,
clonedModel: null,
primaryResource: Ember.computed.alias('clonedModel'),
hostOptions: null,
didReceiveAttrs() {
this._super(...arguments);
this.setProperties({
hostOptions: this.get(`hostTemplate.publicValues.${this.get('hostTemplate.driver')}Config`),
clonedModel: this.get('host').clone(),
});
},
actions: {
saveTemp() {
if (this.get('selectedHostTemplate')) {
if (this.get('selectedHostTemplate.accountId')) {
this.buildModelOut(this.get('model'), this.get('selectedHostTemplate.id')).then((/*result*/) => {
this.sendAction('save');
});
} else {
this.get('selectedHostTemplate').save().then((hstTemplate) => {
hstTemplate.waitForNotTransitioning().then(() => {
this.buildModelOut(this.get('model'), this.get('selectedHostTemplate.id')).then((/*result*/) => {
this.sendAction('save');
});
});
});
}
} else {
this.buildModelOut(this.get('model')).then((/*result*/) => {
this.sendAction('save');
});
}
},
},
buildModelOut: function(modelIn, hostId=null) {
var modelOut = modelIn;
if (hostId) {
Ember.$.extend(modelOut, {hostTemplateId: hostId});
}
modelOut.setProperties({
rancherConfig: {
flavor: this.get('config.uiOptions.id')
}
});
let errors = [];
return modelOut.save().catch((err) => {
errors.pushObject(err);
}).finally(() => {
if ( errors.length ) {
this.set('errors', errors);
} else {
this.set('errors', null);
}
});
}
});

View File

@ -1,87 +1 @@
<div class="hosts-cloud-add">
<section class="header clearfix">
<div class="row">
<div class="mb-0">
<h1>
{{t 'hostsPage.cloudHostsPage.addPage.header'}}
</h1>
</div>
</div>
</section>
<section class="mt-20">
<form>
<section class="horizontal-form">
<div class="row addtl-info">
<div class="col span-4">
<div class="nav-boxes driver">
<div class="nav-box-item driver machine-driver active {{config.provider}}"></div>
</div>
</div>
<div class="col span-8">
<div class="price">
{{#tooltip-element type="tooltip-basic" model=(concat (format-number config.uiOptions.pricePerHour style='currency' currency='USD') (t 'hostsPage.cloudHostsPage.favoritesPage.pricePerHour')) tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="cloud-host-launch"}}
<div class="inline-block">
{{#if config.provider}}
{{#if (eq config.provider 'digitalocean') }}
{{format-number config.uiOptions.pricePerMonth style='currency' currency='USD'}}<span class="addon">{{t 'hostsPage.cloudHostsPage.favoritesPage.price'}}</span>
{{else}}
{{format-number config.uiOptions.pricePerMonth style='currency' currency='USD'}}<span class="addon">{{t 'hostsPage.cloudHostsPage.favoritesPage.price'}}</span>
{{/if}}
{{/if}}
</div>
{{/tooltip-element}}
</div>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{config.uiOptions.displayName}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{config.uiOptions.realm}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.memory'}}</label>
{{config.uiOptions.memory}}{{t 'hostsPage.cloudHostsPage.addPage.memStUnit'}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.storage'}}</label>
{{config.uiOptions.storage}}{{t 'hostsPage.cloudHostsPage.addPage.memStUnit'}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.transfer'}}</label>
{{config.uiOptions.transfer}}{{t 'hostsPage.cloudHostsPage.addPage.transferUnit'}}
</div>
</div>
</div>
<div class="container-fluid">
{{partial "host/add-common"}}
<hr />
{{#if (or (eq config.uiOptions.apiKeySupport 'byokey') (eq config.uiOptions.apiKeySupport 'both'))}}
{{add-host-template
templates=hostTemplates
provider=config.pretty_provider
selectedKey=(mut selectedHostTemplate)
}}
<hr/>
{{/if}}
<div class="row">
<div class="col span-12">
{{#advanced-section}}
{{form-user-labels initialLabels=model.labels setLabels=(action 'setLabels')}}
{{/advanced-section}}
</div>
</div>
</div>
{{top-errors errors=errors}}
{{save-cancel save="saveTemp" cancel=cancel createLabel='hostsPage.cloudHostsPage.addPage.launch'}}
</section>
</form>
</section>
</div>
{{partial 'host/host-templates/host-launch'}}

View File

@ -20,7 +20,7 @@ export default Ember.Component.extend(ManageLabels, {
this.$('INPUT.key').last()[0].focus();
});
}
},
},
didReceiveAttrs() {
@ -31,6 +31,7 @@ export default Ember.Component.extend(ManageLabels, {
}
},
init() {
this._super(...arguments);

View File

@ -11,22 +11,39 @@ let isOptimized=[
];
export default Ember.Component.extend(Driver, {
driverName : 'aliyunecs',
aliyunecsConfig : Ember.computed.alias('model.aliyunecsConfig'),
isOptimized : isOptimized,
driverName: 'aliyunecs',
aliyunecsConfig: Ember.computed.alias('model.publicValues.aliyunecsConfig'),
isOptimized: isOptimized,
bootstrap: function() {
let config = this.get('store').createRecord({
type : 'aliyunecsConfig',
type: 'aliyunecsConfig',
});
this.set('model', this.get('store').createRecord({
type: 'host',
aliyunecsConfig: config,
type: 'hostTemplate',
driver: 'aliyunecs',
publicValues: {
aliyunecsConfig: config
},
secretValues: {
aliyunecsConfig: {
accessKeySecret: ''
}
}
}));
//this.set('editing', false);
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
});

View File

@ -1,9 +1,19 @@
<section class="horizontal-form">
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.accountSection'}}</span>
@ -12,207 +22,207 @@
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.accessKey.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.accessKeyId placeholder=(t 'machine.driverAliyunecs.accessKey.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.accessKey.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.accessKeyId placeholder=(t 'machine.driverAliyunecs.accessKey.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.accessKeySecret.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.accessKeySecret placeholder=(t 'machine.driverAliyunecs.accessKeySecret.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.accessKeySecret.label'}}</label>
</div>
<div class="col span-4">
{{input type="password" class="form-control" value=model.secretValues.aliyunecsConfig.accessKeySecret placeholder=(t 'machine.driverAliyunecs.accessKeySecret.placeholder')}}
</div>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.apiEndpoint.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.apiEndpoint placeholder=(t 'machine.driverAliyunecs.apiEndpoint.placeholder')}}
</div>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.instanceSection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceDescription.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.description placeholder=(t 'machine.driverAliyunecs.instanceDescription.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceType.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.instanceType placeholder=(t 'machine.driverAliyunecs.instanceType.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.apiEndpoint.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.apiEndpoint placeholder=(t 'machine.driverAliyunecs.apiEndpoint.placeholder')}}
</div>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.systemImage.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.imageId placeholder=(t 'machine.driverAliyunecs.systemImage.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceTag.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.tag placeholder=(t 'machine.driverAliyunecs.instanceTag.placeholder')}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.instanceOptionsSection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceDescription.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.description placeholder=(t 'machine.driverAliyunecs.instanceDescription.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.internetMaxBandwidth.label'}}</label>
</div>
<div class="col span-4">
<div class="input-group">
{{input type="text" class="form-control" value=aliyunecsConfig.internetMaxBandwidth placeholder=(t 'machine.driverAliyunecs.internetMaxBandwidth.placeholder')}}
<div class="input-group-addon bg-default">Mbps</div>
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.aliyunSLB.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.slbId placeholder=(t 'machine.driverAliyunecs.aliyunSLB.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceType.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.instanceType placeholder=(t 'machine.driverAliyunecs.instanceType.placeholder')}}
</div>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.systemImage.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.imageId placeholder=(t 'machine.driverAliyunecs.systemImage.placeholder')}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.storageSection'}}</span>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.instanceTag.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.tag placeholder=(t 'machine.driverAliyunecs.instanceTag.placeholder')}}
</div>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.internetMaxBandwidth.label'}}</label>
</div>
<div class="col span-4">
<div class="input-group">
{{input type="text" class="form-control" value=aliyunecsConfig.internetMaxBandwidth placeholder=(t 'machine.driverAliyunecs.internetMaxBandwidth.placeholder')}}
<div class="input-group-addon bg-default">Mbps</div>
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.aliyunSLB.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.slbId placeholder=(t 'machine.driverAliyunecs.aliyunSLB.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.isOptimized.label'}}</label>
</div>
<div class="col span-4">
{{!--{{input type="text" class="form-control" value=aliyunecsConfig.isOptimized placeholder=(t 'machine.driverAliyunecs.isOptimized.placeholder')}}--}}
{{new-select
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.storageSection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.isOptimized.label'}}</label>
</div>
<div class="col span-4">
{{!--{{input type="text" class="form-control" value=aliyunecsConfig.isOptimized placeholder=(t 'machine.driverAliyunecs.isOptimized.placeholder')}}--}}
{{new-select
classNames="form-control"
content=isOptimized
optionLabelPath='value'
value=aliyunecsConfig.isOptimized
}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.systemDiskCategory.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.systemDiskCategory placeholder=(t 'machine.driverAliyunecs.systemDiskCategory.placeholder')}}
</div>
}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.dataDiskCategory.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.diskCategory placeholder=(t 'machine.driverAliyunecs.dataDiskCategory.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.systemDiskCategory.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.systemDiskCategory placeholder=(t 'machine.driverAliyunecs.systemDiskCategory.placeholder')}}
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.dataDiskSize.label'}}</label>
</div>
<div class="col span-4">
<div class="input-group">
{{input type="text" class="form-control" value=aliyunecsConfig.diskSize placeholder=(t 'machine.driverAliyunecs.dataDiskSize.placeholder')}}
<div class="input-group-addon bg-default">GB</div>
</div>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.dataDiskCategory.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.diskCategory placeholder=(t 'machine.driverAliyunecs.dataDiskCategory.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.region.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.region placeholder=(t 'machine.driverAliyunecs.region.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.dataDiskSize.label'}}</label>
</div>
<div class="col span-4">
<div class="input-group">
{{input type="text" class="form-control" value=aliyunecsConfig.diskSize placeholder=(t 'machine.driverAliyunecs.dataDiskSize.placeholder')}}
<div class="input-group-addon bg-default">GB</div>
</div>
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.zone.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.zone placeholder=(t 'machine.driverAliyunecs.zone.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.region.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.region placeholder=(t 'machine.driverAliyunecs.region.placeholder')}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.networkSection'}}</span>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.zone.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.zone placeholder=(t 'machine.driverAliyunecs.zone.placeholder')}}
</div>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.networkSection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.routeCIDR.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.routeCidr placeholder=(t 'machine.driverAliyunecs.routeCIDR.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.routeCIDR.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.routeCidr placeholder=(t 'machine.driverAliyunecs.routeCIDR.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.vpcId.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.vpcId placeholder=(t 'machine.driverAliyunecs.vpcId.placeholder')}}
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.vpcId.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.vpcId placeholder=(t 'machine.driverAliyunecs.vpcId.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.vswitchId.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.vswitchId placeholder=(t 'machine.driverAliyunecs.vswitchId.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.vswitchId.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.vswitchId placeholder=(t 'machine.driverAliyunecs.vswitchId.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.privateIp.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.privateIp placeholder=(t 'machine.driverAliyunecs.privateIp.placeholder')}}
</div>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.privateIp.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.privateIp placeholder=(t 'machine.driverAliyunecs.privateIp.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.privateAddressOnly.label'}}</label>
</div>
<div class="col span-4">
{{input type="checkbox" class="form-control" checked=aliyunecsConfig.privateAddressOnly}}
</div>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.securitySection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.securityGroup.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.securityGroup placeholder=(t 'machine.driverAliyunecs.securityGroup.placeholder')}}
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.privateAddressOnly.label'}}</label>
</div>
<div class="col span-4">
{{input type="checkbox" class="form-control" checked=aliyunecsConfig.privateAddressOnly}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.sshPassword.label'}}</label>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.securitySection'}}</span>
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.securityGroup.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.securityGroup placeholder=(t 'machine.driverAliyunecs.securityGroup.placeholder')}}
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverAliyunecs.sshPassword.label'}}</label>
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.sshPassword placeholder=(t 'machine.driverAliyunecs.sshPassword.placeholder')}}
</div>
<div class="col span-4">
{{input type="text" class="form-control" value=aliyunecsConfig.sshPassword placeholder=(t 'machine.driverAliyunecs.sshPassword.placeholder')}}
</div>
</div>

View File

@ -106,7 +106,7 @@ export default Ember.Component.extend(Driver, {
prefs : Ember.inject.service(),
driverName : 'amazonec2',
model : null,
amazonec2Config : Ember.computed.alias('model.amazonec2Config'),
amazonec2Config : Ember.computed.alias('model.publicValues.amazonec2Config'),
clients : null,
allSubnets : null,
@ -139,19 +139,37 @@ export default Ember.Component.extend(Driver, {
type : 'amazonec2Config',
region : 'us-west-2',
instanceType : 't2.micro',
securityGroup : 'rancher-machine',
securityGroup : ['rancher-machine',],
zone : 'a',
rootSize : 16,
rootSize : '16',
accessKey : pref.accessKey||'',
secretKey : pref.secretKey||'',
});
this.set('model', this.get('store').createRecord({
type : 'host',
amazonec2Config : config,
type: 'hostTemplate',
driver: 'amazonec2',
publicValues: {
amazonec2Config: config
},
secretValues: {
amazonec2Config: {
secretKey: pref.secretKey||'',
}
}
}));
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
init: function() {
this._super(...arguments);
@ -191,15 +209,6 @@ export default Ember.Component.extend(Driver, {
});
}.observes('context.step'),
selectedSecurityGroupChanged: Ember.observer('whichSecurityGroup', 'isStep5', function() {
if (this.get('isStep5') && this.get('whichSecurityGroup') === 'custom') {
Ember.run.scheduleOnce('afterRender', this, function() {
this.initMultiselect();
});
}
}),
actions: {
awsLogin: function() {
let self = this;
@ -207,13 +216,13 @@ export default Ember.Component.extend(Driver, {
this.set('step',2);
this.set('amazonec2Config.accessKey', (this.get('amazonec2Config.accessKey')||'').trim());
this.set('amazonec2Config.secretKey', (this.get('amazonec2Config.secretKey')||'').trim());
this.set('model.secretValues.amazonec2Config.secretKey', (this.get('model.secretValues.amazonec2Config.secretKey')||'').trim());
let subnets = [];
let rName = this.get('amazonec2Config.region');
let ec2 = new AWS.EC2({
accessKeyId : this.get('amazonec2Config.accessKey'),
secretAccessKey : this.get('amazonec2Config.secretKey'),
secretAccessKey : this.get('model.secretValues.amazonec2Config.secretKey'),
region : rName,
});
@ -400,76 +409,6 @@ export default Ember.Component.extend(Driver, {
},
},
initMultiselect: function() {
var view = this;
var opts = {
maxHeight: 200,
buttonClass: 'btn bg-default',
buttonWidth: '100%',
templates: {
li: '<li><a tabindex="0"><label></label></a></li>',
},
buttonText: function(options/*, select*/) {
var label = 'Security Groups: ';
if ( options.length === 0 )
{
label += 'None';
}
else if ( options.length === 1 )
{
label += $(options[0]).text();
}
else
{
label += options.length + ' Selected';
}
return label;
},
onChange: function(/*option, checked*/) {
var self = this;
var options = $('option', this.$select);
var selectedOptions = this.getSelected();
var allOption = $('option[value="ALL"]',this.$select)[0];
var isAll = $.inArray(allOption, selectedOptions) >= 0;
if ( isAll )
{
options.each(function(k, option) {
var $option = $(option);
if ( option !== allOption )
{
self.deselect($(option).val());
$option.prop('disabled',true);
$option.parent('li').addClass('disabled');
}
});
// @TODO Figure out why deslect()/select() doesn't fix the state in the ember object and remove this hackery...
var ary = view.get('instance.' + (this.$select.hasClass('select-cap-add') ? 'capAdd' : 'capDrop'));
ary.clear();
ary.pushObject('ALL');
}
else
{
options.each(function(k, option) {
var $option = $(option);
$option.prop('disabled',false);
$option.parent('li').removeClass('disabled');
});
}
this.$select.multiselect('refresh');
}
};
this.$('.existing-security-groups').multiselect(opts);
},
selectedZone: Ember.computed('amazonec2Config.{region,zone}', {
get: function() {
let config = this.get('amazonec2Config');

View File

@ -1,6 +1,20 @@
<section class="horizontal-form">
<form>
<div class="container-fluid">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAmazon.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mb-20">
<span>{{t 'machine.driverAmazon.accessSection'}}</span>
</div>
@ -39,7 +53,7 @@
</div>
<div class="col span-8">
{{#if isStep1}}
{{input type="password" name="password" classNames="form-control" placeholder=(t 'machine.driverAmazon.secretKey.placeholder') value=amazonec2Config.secretKey}}
{{input type="password" name="password" classNames="form-control" placeholder=(t 'machine.driverAmazon.secretKey.placeholder') value=model.secretValues.amazonec2Config.secretKey}}
{{else}}
<div class="text-muted text-italic">{{t 'machine.driverAmazon.secretKey.provided'}}</div>
{{/if}}
@ -151,25 +165,14 @@
</div>
<div class="col span-8">
{{#if isStep5}}
<div class="radio">
<label>
{{radio-button selection=whichSecurityGroup value="default"}}
{{#if defaultSecurityGroup}}
{{t 'machine.driverAmazon.securityGroup.defaultExisting' groupName=defaultSecurityGroupName htmlSafe=true}}
{{else}}
{{t 'machine.driverAmazon.securityGroup.defaultCreate' groupName=defaultSecurityGroupName htmlSafe=true}}
{{/if}}
</label>
</div>
{{#if (and settings.isRancher (not isCustomSecurityGroup))}}
<p class="text-info ml-20"><a href="{{settings.docsBase}}/hosts/amazon/#required-ports-for-rancher-to-work" target="_blank">{{t 'machine.driverAmazon.portHelp.link'}}</a> {{t 'machine.driverAmazon.portHelp.text'}}</p>
{{/if}}
<div class="radio">
<div class="radio pt-10">
<label>
{{radio-button selection=whichSecurityGroup value="custom"}}
{{t 'machine.driverAmazon.securityGroup.custom'}}
{{t 'machine.driverAmazon.securityGroup.choose'}}
</label>
</div>
@ -226,14 +229,6 @@
<section class="horizontal-form {{unless isGteStep7 'hide'}}" style="padding-top: 0;">
<div class="container-fluid">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAmazon.instanceSection'}}</span>
</div>
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAmazon.instanceOptionsSection'}}</span>
</div>

View File

@ -3,7 +3,7 @@ import { regions, sizes, storageTypes, environments } from 'ui/utils/azure-choic
import Driver from 'ui/mixins/driver';
export default Ember.Component.extend(Driver, {
azureConfig : Ember.computed.alias('model.azureConfig'),
azureConfig : Ember.computed.alias('model.publicValues.azureConfig'),
environments : environments.sortBy('value'),
sizeChoices : sizes.sortBy('value'),
driverName : 'azure',
@ -31,13 +31,20 @@ export default Ember.Component.extend(Driver, {
type : 'azureConfig',
subscriptionId : '',
clientId : '',
clientSecret : '',
openPort : ['500/udp','4500/udp'],
});
this.set('model', this.get('store').createRecord({
type: 'host',
azureConfig: config,
type: 'hostTemplate',
driver: 'azure',
publicValues: {
azureConfig: config
},
secretValues: {
azureConfig: {
clientSecret : '',
}
}
}));
this.set('editing', false);
@ -125,11 +132,10 @@ export default Ember.Component.extend(Driver, {
}),
validate: function() {
this._super();
let errors = this.get('errors')||[];
let errors = [];
this.set('prefix',(this.get('prefix')||'').toLowerCase());
let name = this.get('model.hostname');
let name = this.get('model.name');
if ( name.length < 4 || name.length > 62 ) {
errors.push('Name must be between 4 and 62 characters long');
}
@ -146,7 +152,7 @@ export default Ember.Component.extend(Driver, {
errors.push('Client ID is requried');
}
if (!this.get('azureConfig.clientSecret') ) {
if (!this.get('model.secretValues.azureConfig.clientSecret') ) {
errors.push('Client Secret is requried');
}

View File

@ -1,8 +1,18 @@
<section class="horizontal-form">
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAzure.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAzure.placementSection'}}</span>
@ -61,9 +71,9 @@
<div class="col span-6">
<label class="pb-5">{{t 'machine.driverAzure.clientSecret.label'}}{{field-required}}</label>
{{input type="password" value=azureConfig.clientSecret classNames="form-control"}}
{{input type="password" value=model.secretValues.azureConfig.clientSecret classNames="form-control"}}
</div>
</div>
@ -113,7 +123,7 @@
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAzure.instanceSection'}}</span>
<span>{{t 'machine.driverAzure.instanceOptionsSection'}}</span>
</div>
<div class="row">
@ -138,7 +148,7 @@
<label class="pb-5">{{t 'machine.driverAzure.dockerPort.label'}}</label>
{{input type="text" value=azureConfig.dockerPort classNames="form-control" placeholder=(t 'machine.driverAzure.dockerPort.placeholder')}}
</div>
<div class="col span-6">
<label class="pb-5">{{t 'machine.driverAzure.openPort.label'}}</label>
{{input type="text" value=openPorts classNames="form-control" placeholder=(t 'machine.driverAzure.openPort.placeholder')}}

View File

@ -49,7 +49,7 @@
<li>
{{t 'machine.driverCustom.step3'}}
<div class="mt-10">
{{form-user-labels setLabels=(action 'setLabels')}}
{{form-user-labels setLabels=(action 'setLabels') expandAll=null}}
</div>
</li>
<li>

View File

@ -25,7 +25,7 @@ export default Ember.Component.extend(Driver, {
driverName: 'digitalocean',
regionChoices: null,
model: null,
digitaloceanConfig: Ember.computed.alias('model.digitaloceanConfig'),
digitaloceanConfig: Ember.computed.alias('model.publicValues.digitaloceanConfig'),
step1: true,
sizeChoices: null,
imageChoices: null,
@ -102,24 +102,31 @@ export default Ember.Component.extend(Driver, {
bootstrap: function() {
let config = this.get('store').createRecord({
type : 'digitaloceanConfig',
accessToken : '',
size : '1gb',
region : 'nyc3',
image : 'ubuntu-16-04-x64'
});
this.set('model', this.get('store').createRecord({
type: 'host',
digitaloceanConfig: config,
type: 'hostTemplate',
driver: 'digitalocean',
publicValues: {
digitaloceanConfig: config
},
secretValues: {
digitaloceanConfig: {
accessToken : '',
}
}
}));
},
validate: function() {
this._super();
// this._super();
let errors = this.get('errors')||[];
let name = this.get('model.hostname')||'';
let accessToken = this.get('digitaloceanConfig.accessToken')||'';
let name = this.get('model.name')||'';
let accessToken = this.get('model.secretValues.digitaloceanConfig.accessToken')||'';
if ( name.length > 200 ) {
errors.push('"name" should be 1-200 characters long');
@ -157,7 +164,7 @@ export default Ember.Component.extend(Driver, {
return fetch(url, {
headers: {
'Accept': 'application/json',
'X-Api-Auth-Header': 'Bearer ' + this.get('model.digitaloceanConfig.accessToken'),
'X-Api-Auth-Header': 'Bearer ' + this.get('model.secretValues.digitaloceanConfig.accessToken'),
},
}).then((res) => {
let body = res.body;

View File

@ -1,6 +1,21 @@
<section class="horizontal-form">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverDigitalocean.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
{{#if step1}}
<form>
<div class="over-hr mb-20">
<span>{{t 'machine.driverDigitalocean.accountSection'}}</span>
</div>
@ -10,7 +25,7 @@
<label>{{t 'machine.driverDigitalocean.accessToken.label'}}</label>
</div>
<div class="col span-10">
{{input type="password" value=digitaloceanConfig.accessToken classNames="form-control" placeholder=(t 'machine.driverDigitalocean.accessToken.placeholder')}}
{{input type="password" value=model.secretValues.digitaloceanConfig.accessToken classNames="form-control" placeholder=(t 'machine.driverDigitalocean.accessToken.placeholder')}}
<p class="text-info">{{t 'machine.driverDigitalocean.accessToken.help' htmlSafe=true}}</p>
</div>
</div>
@ -20,17 +35,13 @@
{{#if gettingData}}
<button class="btn bg-primary btn-disabled"><i class="icon icon-spinner icon-spin"></i> {{t 'generic.loading'}}</button>
{{else}}
<button {{action "getData" 'region'}} class="btn bg-primary" disabled={{not model.digitaloceanConfig.accessToken}}>{{t 'machine.driverDigitalocean.authAccountButton'}}</button>
<button {{action "getData" 'region'}} class="btn bg-primary" disabled={{not model.secretValues.digitaloceanConfig.accessToken}}>{{t 'machine.driverDigitalocean.authAccountButton'}}</button>
{{/if}}
<button {{action "cancel"}} class="btn bg-transparent">{{t 'generic.cancel'}}</button>
</div>
</form>
{{else}}
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverDigitalocean.regionSection'}}</span>
</div>
@ -49,7 +60,7 @@
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverDigitalocean.instanceSection'}}</span>
<span>{{t 'machine.driverDigitalocean.instanceOptionsSection'}}</span>
</div>
<div class="row inline-form">

View File

@ -40,7 +40,7 @@ let RANCHER_INGRESS_RULES = [
export default Ember.Component.extend(Driver, {
driverName : 'exoscale',
model : null,
exoscaleConfig : Ember.computed.alias('model.exoscaleConfig'),
exoscaleConfig : Ember.computed.alias('model.publicValues.exoscaleConfig'),
allDiskSizes : null,
allInstanceProfiles : null,
@ -68,19 +68,38 @@ export default Ember.Component.extend(Driver, {
bootstrap: function() {
let config = this.get('store').createRecord({
type: 'exoscaleConfig',
apiKey: '',
apiSecretKey: '',
exoscaleApiKey: '',
diskSize: 50,
instanceProfile: 'small',
securityGroup: 'rancher-machine'
});
this.set('model', this.get('store').createRecord({
type: 'host',
exoscaleConfig: config
type: 'hostTemplate',
driver: 'exoscale',
publicValues: {
exoscaleConfig: config
},
secretValues: {
exoscaleConfig: {
exoscaleApiSecretKey: '',
}
}
}));
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
afterInit: function() {
this._super();
@ -109,8 +128,8 @@ export default Ember.Component.extend(Driver, {
this.set('errors', null);
this.set('step', 2);
this.set('exoscaleConfig.apiKey', (this.get('exoscaleConfig.apiKey')||'').trim());
this.set('exoscaleConfig.apiSecretKey', (this.get('exoscaleConfig.apiSecretKey')||'').trim());
this.set('exoscaleConfig.exoscaleApiKey', (this.get('exoscaleConfig.exoscaleApiKey')||'').trim());
this.set('model.secretValues.exoscaleConfig.exoscaleApiSecretKey', (this.get('model.secretValues.exoscaleConfig.exoscaleApiSecretKey')||'').trim());
this.apiRequest('listSecurityGroups').then((res) => {
let groups = [];
@ -271,7 +290,7 @@ export default Ember.Component.extend(Driver, {
let url = this.get('app.proxyEndpoint') + '/' + this.exoscaleApi;
params = params || {};
params.command = command;
params.apiKey = this.get('exoscaleConfig.apiKey');
params.apiKey = this.get('exoscaleConfig.exoscaleApiKey');
params.response = 'json';
return ajaxPromise({url: url,
@ -293,7 +312,7 @@ export default Ember.Component.extend(Driver, {
.sort()
.join('&');
settings.data += '&signature=' + encodeURIComponent(AWS.util.crypto.hmac(
this.get('exoscaleConfig.apiSecretKey'), qs, 'base64', 'sha1'));
this.get('model.secretValues.exoscaleConfig.exoscaleApiSecretKey'), qs, 'base64', 'sha1'));
return true;
},
data: params}, true);

View File

@ -1,6 +1,21 @@
<section class="horizontal-form">
<form>
<div class="container-fluid">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverExoscale.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mb-20">
<span>{{t 'machine.driverExoscale.accountSection'}}</span>
</div>
@ -11,9 +26,9 @@
</div>
<div class="col span-10">
{{#if isStep1}}
{{input type="text" name="username" classNames="form-control" placeholder=(t 'machine.driverExoscale.apiKey.placeholder') value=exoscaleConfig.apiKey}}
{{input type="text" name="username" classNames="form-control" placeholder=(t 'machine.driverExoscale.apiKey.placeholder') value=exoscaleConfig.exoscaleApiKey}}
{{else}}
<div>{{exoscaleConfig.apiKey}}</div>
<div>{{exoscaleConfig.exoscaleApiKey}}</div>
{{/if}}
</div>
</div>
@ -23,7 +38,7 @@
</div>
<div class="col span-10">
{{#if isStep1}}
{{input type="password" name="password" classNames="form-control" placeholder=(t 'machine.driverExoscale.secretKey.placeholder') value=exoscaleConfig.apiSecretKey}}
{{input type="password" name="password" classNames="form-control" placeholder=(t 'machine.driverExoscale.secretKey.placeholder') value=model.secretValues.exoscaleConfig.exoscaleApiSecretKey}}
{{else}}
<div class="text-muted text-italic">{{t 'machine.driverExoscale.secretKey.provided'}}</div>
{{/if}}
@ -128,13 +143,9 @@
<section class="horizontal-form pt-0 {{unless isGteStep6 'hide'}}">
<div class="container-fluid">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverExoscale.instanceSection'}}</span>
<span>{{t 'machine.driverExoscale.instanceOptionsSection'}}</span>
</div>
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="row inline-form">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverExoscale.instanceProfile.label'}}</label>

View File

@ -12,16 +12,10 @@ export default Ember.Component.extend(Driver, {
schemas : null,
driverOpts : null,
init() {
this._super(...arguments);
this._super();
this.driverChanged();
},
bootstrap() {
let model = this.get('store').createRecord({
type: 'host',
type: 'hostTemplate',
isOfTypeOther: true,
});
this.setProperties({
@ -29,6 +23,16 @@ export default Ember.Component.extend(Driver, {
model: model
});
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
willDestroyElement() {
this.setProperties({
@ -37,50 +41,76 @@ export default Ember.Component.extend(Driver, {
});
},
fieldNames: function() {
fieldNames: Ember.computed('otherDriver', 'model', function() {
let driver = this.get('otherDriver');
if ( driver ) {
return Object.keys(this.get('userStore').getById('schema', driver.toLowerCase()).get('resourceFields'));
}
}.property('otherDriver', 'model'),
}),
driverChanged: function() {
let driver = this.get('otherDriver');
let host = this.get('model');
getSecrets(fields) {
let keys = Object.keys(fields);
let out = [];
keys.forEach((key) => {
if (key.toLowerCase().indexOf('secret') > -1 || key.toLowerCase().indexOf('password') > -1){
out.push(key);
}
})
return out;
},
if ( driver && host) {
if ( !host.get(driver) ) {
host.set(driver, this.get('store').createRecord({ type: driver }));
driverChanged: Ember.on('init', Ember.observer('otherDriver','model', function() {
if (this.get('otherDriver')) {
let driver = this.get('otherDriver').split('C')[0];
let hostTemplate = this.get('model');
let config = this.get('store').createRecord({
type : this.get('otherDriver'),
});
let secrets = this.getSecrets(this.get('userStore').getById('schema', this.get('otherDriver').toLowerCase()).get('resourceFields'));
let secretConfig = {
[this.get('otherDriver')]: {}
}
this.set('driverOpts', host.get(driver));
if (secrets) {
secrets.forEach((secret) => {
secretConfig[secret] = '';
});
}
hostTemplate.setProperties({
driver: driver,
publicValues: {
[this.get('otherDriver')]: config
},
secretValues: {
[this.get('otherDriver')]: secretConfig
},
});
this.set('driverOpts', hostTemplate.get(`publicValues.${this.get('otherDriver')}`));
}
else {
this.set('otherDriver', this.get('otherChoices.firstObject.value'));
}
}.observes('otherDriver','model'),
})),
otherChoices: function() {
otherChoices: Ember.computed('availableDrivers.@each.{hasUi,name}', function() {
let out = [];
this.get('availableDrivers').filterBy('hasUi',false).forEach((driver) => {
out.push({label: driver.name, value: driver.name+'Config'});
});
return out;
}.property('availableDrivers.@each.{hasUi,name}'),
return out.sortBy('name');
}),
willSave() {
// Null out all the drivers that aren't the active one, because the API only accepts one.
let activeDriver = this.get('otherDriver');
let host = this.get('model');
this.get('otherChoices').forEach((choice) => {
let cur = choice.value;
if ( choice.value !== activeDriver ) {
host.set(cur, null);
}
});
// willSave() {
// // Null out all the drivers that aren't the active one, because the API only accepts one.
// debugger;
// let activeDriver = this.get('otherDriver');
// let host = this.get('model');
// this.get('otherChoices').forEach((choice) => {
// let cur = choice.value;
// if ( choice.value !== activeDriver ) {
// host.set(cur, null);
// }
// });
return this._super();
},
// return this._super();
// },
});

View File

@ -1,7 +1,18 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverOther.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverOther.driverSection'}}</span>
@ -13,9 +24,9 @@
</div>
<div class="col span-8">
{{new-select
classNames="form-control"
content=otherChoices
value=otherDriver
classNames="form-control"
content=otherChoices
value=otherDriver
}}
</div>
</div>
@ -26,12 +37,12 @@
{{#each fieldNames as |fieldName|}}
{{api-field
resource=driverOpts
resourceType=otherDriver
field=fieldName
value=(get driverOpts fieldName)
schemas=schemas
typeDocs=typeDocumentations
resource=driverOpts
resourceType=otherDriver
field=fieldName
value=(get driverOpts fieldName)
schemas=schemas
typeDocs=typeDocumentations
}}
{{/each}}

View File

@ -17,7 +17,7 @@ let planChoices = PacketPlans.filter(function(plan) {
export default Ember.Component.extend(Driver, {
driverName : 'packet',
packetConfig : Ember.computed.alias('model.packetConfig'),
packetConfig : Ember.computed.alias('model.publicValues.packetConfig'),
facilityChoices : PacketFacilities,
planChoices : planChoices,
@ -27,7 +27,6 @@ export default Ember.Component.extend(Driver, {
let store = this.get('store');
let config = store.createRecord({
type : 'packetConfig',
apiKey : '',
projectId : '',
os : 'ubuntu_14_04',
facilityCode : 'ewr1',
@ -39,17 +38,29 @@ export default Ember.Component.extend(Driver, {
type: 'host',
packetConfig: config,
}));
this.set('model', this.get('store').createRecord({
type: 'hostTemplate',
driver: 'packet',
publicValues: {
packetConfig: config
},
secretValues: {
packetConfig: {
apiKey : '',
}
}
}));
},
validate: function() {
this._super();
let errors = this.get('errors')||[];
let errors = [];
if (!this.get('packetConfig.projectId') ) {
errors.push('Project ID is required');
}
if (!this.get('packetConfig.apiKey') ) {
if (!this.get('model.secretValues.packetConfig.apiKey') ) {
errors.push('API Key is requried');
}

View File

@ -1,9 +1,19 @@
<form>
<section class="horizontal-form">
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverPacket.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverPacket.accountSection'}}</span>
@ -16,13 +26,13 @@
</div>
<div class="col span-6">
<label>{{t 'machine.driverPacket.apiKey.label'}}{{field-required}}</label>
{{input type="password" name="password" value=packetConfig.apiKey classNames="form-control" placeholder=(t 'machine.driverPacket.apiKey.placeholder')}}
{{input type="password" name="password" value=model.secretValues.packetConfig.apiKey classNames="form-control" placeholder=(t 'machine.driverPacket.apiKey.placeholder')}}
<p class="text-info">{{t 'machine.driverPacket.apiKeyHelp' htmlSafe=true}}</p>
</div>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverPacket.instanceSection'}}</span>
<span>{{t 'machine.driverPacket.instanceOptionsSection'}}</span>
</div>
<div class="row inline-form">

View File

@ -39,7 +39,7 @@ flavorChoices.sort(function(a,b) {
export default Ember.Component.extend(Driver, {
driverName : 'rackspace',
rackspaceConfig : Ember.computed.alias('model.rackspaceConfig'),
rackspaceConfig : Ember.computed.alias('model.publicValues.rackspaceConfig'),
flavorChoices : flavorChoices,
regionChoices : [
{label: 'Dallas (DFW)', value: 'DFW'},
@ -56,14 +56,33 @@ export default Ember.Component.extend(Driver, {
let config = store.createRecord({
type: 'rackspaceConfig',
username: '',
apiKey: '',
region: 'DFW',
flavorId: 'general1-1',
});
this.set('model', this.get('store').createRecord({
type: 'host',
rackspaceConfig: config,
type: 'hostTemplate',
driver: 'rackspace',
publicValues: {
rackspaceConfig: config
},
secretValues: {
rackspaceConfig: {
apiKey: '',
}
}
}));
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
});

View File

@ -2,9 +2,19 @@
<section class="horizontal-form">
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverRackspace.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverRackspace.accountSection'}}</span>
@ -24,7 +34,7 @@
<label>{{t 'machine.driverRackspace.apiKey.label'}}{{field-required}}</label>
</div>
<div class="col span-10">
{{input type="password" value=rackspaceConfig.apiKey classNames="form-control" placeholder=(t 'machine.driverRackspace.apiKey.placeholder')}}
{{input type="password" value=model.secretValues.rackspaceConfig.apiKey classNames="form-control" placeholder=(t 'machine.driverRackspace.apiKey.placeholder')}}
<p class="text-info">{{t 'machine.driverRackspace.accountHelp'}}</p>
</div>
</div>
@ -47,7 +57,7 @@
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverRackspace.instanceSection'}}</span>
<span>{{t 'machine.driverRackspace.instanceOptionsSection'}}</span>
</div>
<div class="row inline-form">

View File

@ -1,181 +0,0 @@
import Ember from 'ember';
import Driver from 'ui/mixins/driver';
import { ajaxPromise } from 'ember-api-store/utils/ajax-promise';
export default Ember.Component.extend(Driver, {
driverName : 'ubiquity',
ubiquityConfig : Ember.computed.alias('model.ubiquityConfig'),
ubiquityHostingApi : 'api.ubiquityhosting.com/v25/api.php',
allZones : null,
allImages : null,
allFlavors : null,
step : 1,
isStep1 : Ember.computed.equal('step',1),
isStep2 : Ember.computed.equal('step',2),
isGteStep3 : Ember.computed.gte('step',3),
bootstrap: function() {
let store = this.get('store');
let config = store.createRecord({
type: 'ubiquityConfig',
apiToken: '',
apiUsername: '',
clientId: '',
flavorId: '',
imageId: '',
zoneId: ''
});
this.set('model', store.createRecord({
type: 'host',
ubiquityConfig: config,
}));
},
willDestroyElement() {
this.set('errors', null);
this.set('step', 1);
},
actions: {
/* Login step */
ubiLogin: function() {
this.set('errors', null);
this.set('step', 2);
this.set('ubiquityConfig.clientId', (this.get('ubiquityConfig.clientId')||'').trim());
this.set('ubiquityConfig.apiUsername', (this.get('ubiquityConfig.apiUsername')||'').trim());
this.set('ubiquityConfig.apiToken', (this.get('ubiquityConfig.apiToken')||'').trim());
Ember.RSVP.hash({
zones: this.getZones(),
flavors: this.getFlavors(),
}).then((hash) => {
this.set('allZones', hash.zones);
this.set('allFlavors', hash.flavors);
if ( !this.get('ubiquityConfig.zoneId') )
{
this.set('ubiquityConfig.zoneId', this.get('allZones.firstObject.id'));
}
if ( !this.get('ubiquityConfig.flavorId') )
{
this.set('ubiquityConfig.flavorId', this.get('allFlavors.firstObject.id'));
}
return this.zoneChange(this.get('ubiquityConfig.zoneId')).then(() => {
this.set('step', 3);
});
}).catch((err) => {
this.set('errors', [err]);
this.set('step', 1);
});
},
setZone(zoneId) {
this.zoneChange(zoneId);
},
},
zoneChange: function(zoneId) {
this.set('ubiquityConfig.zoneId', zoneId);
return this.getImages(zoneId).then((images) => {
this.set('allImages', images);
let existing = this.get('ubiquityConfig.imageId');
if ( !existing || images.filterBy('id', existing).length === 0 ) {
this.set('ubiquityConfig.imageId', images[0].id);
}
});
},
getZones: function() {
return this.apiRequest('list_zones').then((res) => {
return (res.Zones || []).map((zone) => {
return {
id: zone.id,
name: zone.name,
};
});
});
},
getImages: function(zone_id) {
return this.apiRequest('list_images', {zone_id: zone_id, docker_machine: 'true'}).then((res) => {
return (res.Images || []).map((image) => {
return {
id: image.id,
name: image.name,
description: image.cat_desc,
};
});
});
},
getFlavors: function() {
return this.apiRequest('list_flavors').then((res) => {
return (res.Flavors || []).map((flavor) => {
return {
id: flavor.id,
name: flavor.name,
};
});
});
},
apiRequest: function(command, params) {
let url = this.get('app.proxyEndpoint') + '/' + this.ubiquityHostingApi + "?method=cloud." + encodeURIComponent(command);
let auth = this.get('ubiquityConfig.clientId') + ':' + this.get('ubiquityConfig.apiUsername') + ':' + this.get('ubiquityConfig.apiToken');
params = params || {};
return ajaxPromise({
url: url,
method: 'POST',
dataType: 'json',
headers: {
'Accept': 'application/json',
'X-Api-Headers-Restrict': 'Content-Length',
'X-Api-Auth-Header': 'Basic ' + window.btoa(auth),
},
beforeSend: (xhr, settings) => {
xhr.setRequestHeader('Content-Type', 'rancher:' + settings.contentType);
return true;
},
data: params,
params: params
}, true).then((res) => {
if ((res || '') === '') {
return Ember.RSVP.reject('Authentication Failed: Please check the access credentials and that the server is in the list of authorized IP addresses in the Ubiquity console');
} else {
return res;
}
});
},
validate: function() {
this._super();
let errors = this.get('errors')||[];
let name = this.get('model.hostname')||'';
if (name.length < 1 || name.length > 200) {
errors.push('"name" should be 1-200 characters long');
}
if (name.match(/[^a-z0-9-]/i)) {
errors.push('"name" can only contain letters, numbers, and hyphen');
}
if (errors.get('length')) {
this.set('errors',errors);
return false;
}
return true;
},
});

View File

@ -1,119 +0,0 @@
<section class="horizontal-form">
<form name="login">
<div class="container-fluid">
<div class="over-hr mb-20">
<span>{{t 'machine.driverUbiquity.accountSection'}}</span>
</div>
<div class="row {{if isStep1 'inline-form'}}">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.clientId.label'}}</label>
</div>
<div class="col span-10">
{{#if isStep1}}
{{input type="text" name="clientId" classNames="form-control" placeholder=(t 'machine.driverUbiquity.clientId.placeholder') value=ubiquityConfig.clientId}}
{{else}}
<div>{{ubiquityConfig.clientId}}</div>
{{/if}}
</div>
</div>
<div class="row {{if isStep1 'inline-form'}}">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.apiUsername.label'}}</label>
</div>
<div class="col span-10">
{{#if isStep1}}
{{input type="text" name="apiUsername" classNames="form-control" placeholder=(t 'machine.driverUbiquity.apiUsername.placeholder') value=ubiquityConfig.apiUsername}}
{{else}}
<div>{{ubiquityConfig.apiUsername}}</div>
{{/if}}
</div>
</div>
<div class="row {{if isStep1 'inline-form'}}">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.apiToken.label'}}</label>
</div>
<div class="col span-10">
{{#if isStep1}}
{{input type="password" name="apiToken" classNames="form-control" placeholder=(t 'machine.driverUbiquity.apiToken.placeholder') value=ubiquityConfig.apiToken}}
{{else}}
<div class="text-muted text-italic">{{t 'machine.driverUbiquity.apiToken.provided'}}</div>
{{/if}}
{{#if isStep1}}
<p class="text-info">{{t 'machine.driverUbiquity.accountHelp' htmlSafe=true}}</p>
{{/if}}
</div>
</div>
</div>
{{#if isStep1}}
{{top-errors errors=errors}}
<div class="footer-actions">
<button {{action "ubiLogin"}} name="submit" class="btn bg-primary">{{t 'machine.driverUbiquity.loginAction'}}</button>
<button {{action "cancel"}} class="btn bg-transparent">{{t 'generic.cancel'}}</button>
</div>
{{/if}}
</form>
</section>
<section class="horizontal-form pt-0 {{unless isStep2 'hide'}}">
<div class="text-center">
<i class="icon icon-spinner icon-spin"></i> {{t 'machine.driverUbiquity.loadingInstance'}}
</div>
</section>
<section class="horizontal-form pt-0 {{unless isGteStep3 'hide'}}">
<div class="container-fluid">
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverUbiquity.instanceSection'}}</span>
</div>
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverUbiquity.regionSection'}}</span>
</div>
<div class="row inline-form">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.region.label'}}</label>
</div>
<div class="col span-10">
<select class="form-control" onchange={{action "setZone" target.value}}>
{{#each allZones as |choice|}}
<option value={{choice.id}} selected={{eq ubiquityConfig.zoneId choice.id}}>{{choice.name}}</option>
{{/each}}
</select>
</div>
</div>
<div class="row inline-form">
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.image.label'}}</label>
</div>
<div class="col span-4">
<select class="form-control" onchange={{action (mut ubiquityConfig.imageId) value="target.value"}}>
{{#each allImages as |choice|}}
<option value={{choice.id}} selected={{eq ubiquityConfig.imageId choice.id}}>{{choice.name}}</option>
{{/each}}
</select>
</div>
<div class="col span-2 col-inline">
<label>{{t 'machine.driverUbiquity.flavor.label'}}</label>
</div>
<div class="col span-4">
<select class="form-control" onchange={{action (mut ubiquityConfig.flavorId) value="target.value"}}>
{{#each allFlavors as |choice|}}
<option value={{choice.id}} selected={{eq ubiquityConfig.flavorId choice.id}}>{{choice.name}}</option>
{{/each}}
</select>
</div>
</div>
{{partial "host/add-options"}}
</div>
{{top-errors errors=errors}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -4,7 +4,7 @@ import Driver from 'ui/mixins/driver';
export default Ember.Component.extend(Driver, {
driverName : 'vmwarevsphere',
model : null,
config : Ember.computed.alias('model.vmwarevsphereConfig'),
config : Ember.computed.alias('model.publicValues.vmwarevsphereConfig'),
showEngineUrl : false,
bootstrap: function() {
@ -17,9 +17,27 @@ export default Ember.Component.extend(Driver, {
});
this.set('model', this.get('store').createRecord({
type: 'host',
vmwarevsphereConfig: config,
engineInstallUrl: '',
type: 'hostTemplate',
driver: 'vmwarevsphere',
publicValues: {
vmwarevsphereConfig: config
},
secretValues: {
vmwarevsphereConfig: {
password: '',
}
}
}));
},
validate() {
let errors = [];
if ( !this.get('model.name') ) {
errors.push('Name is required');
}
this.set('errors', errors);
return errors.length === 0;
},
});

View File

@ -2,9 +2,21 @@
<section class="horizontal-form">
<div class="container-fluid">
{{#if showNameScale}}
{{partial "host/add-common"}}
{{/if}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverVsphere.instanceSection'}}</span>
</div>
<div class="row mb-20">
{{form-name-description
name=model.name
description=model.description
nameRequired=true
namePlaceholder="hostPartial.host.addCommon.new.form.name.placeholder"
descriptionShown=true
descriptionExpanded=true
}}
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverVsphere.accountSection'}}</span>
@ -37,12 +49,12 @@
<label>{{t 'machine.driverVsphere.password.label'}}{{field-required}}</label>
</div>
<div class="col span-4">
{{input type="password" value=config.password classNames="form-control"}}
{{input type="password" value=model.secretValues.vmwarevsphereConfig.password classNames="form-control"}}
</div>
</div>
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverVsphere.instanceSection'}}</span>
<span>{{t 'machine.driverVsphere.instanceOptionsSection'}}</span>
</div>
<div class="row">

View File

@ -0,0 +1,8 @@
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
savedHost() {},
completed() {},
}
});

50
app/custom-host/route.js Normal file
View File

@ -0,0 +1,50 @@
import Ember from 'ember';
const { getOwner } = Ember;
export default Ember.Route.extend({
access : Ember.inject.service(),
projects : Ember.inject.service(),
settings : Ember.inject.service(),
host : Ember.inject.service(),
backTo : null,
actions: {
cancel() {
this.send('goBack');
},
goBack() {
if ( this.get('backTo') === 'waiting' ) {
this.transitionTo('authenticated.project.waiting');
} else {
this.transitionTo('hosts.templates');
}
}
},
activate() {
let appRoute = getOwner(this).lookup('route:application');
this.set('previousOpts', {name: appRoute.get('previousRoute'), params: appRoute.get('previousParams')});
},
// Loads all the machine drivers and selects the active ones with a corresponding schema into machineDrivers
beforeModel(/*transition*/) {
this._super(...arguments);
var hs = this.get('host');
return hs.loadAllDrivers().then((drivers) => {
this.set('machineDrivers', drivers);
});
},
model(params) {
this.set('backTo', params.backTo);
var hs = this.get('host');
return hs.getModel(params).then((hash) => {
return hash;
});
},
});

View File

@ -0,0 +1,13 @@
<section class="header clearfix">
<h1>
{{#link-to "infrastructure-tab"}}{{t 'hostsPage.new.header.linkTo'}}{{/link-to}}
{{t 'hostsPage.new.header.text'}}
</h1>
</section>
{{component "machine/driver-custom"
cancel=(route-action "cancel")
driver='custom'
completed=(action "completed")
goBack=(route-action "goBack")
}}
<!-- {{add-host model=model driver="custom" completed=(action "completed") goBack=(route-action "goBack") savedHost=(action "savedHost") showPicker=false}} -->

View File

@ -0,0 +1,9 @@
import Ember from 'ember';
export function hostPublicValues(params/*, hash*/) {
var [host] = params;
var pv = host.publicValues[`${host.driver}Config`];
return pv;
}
export default Ember.Helper.helper(hostPublicValues);

View File

@ -1,20 +1,7 @@
import Ember from 'ember';
const PROVIDERS = [
{
id: 'amazonec2',
class: 'amazonec2'
},
{
id: 'digitalocean',
class: 'rancherdo'
},
{
id: 'packet',
class: 'packet '
},
]
import C from 'ui/utils/constants';
export function parseHostIcon(params/*, hash*/) {
return PROVIDERS.findBy('id', params[0]).class || 'other';
return C.MACHINE_DRIVER_IMAGES[params[0].toUpperCase()] || 'other';
}
export default Ember.Helper.helper(parseHostIcon);

View File

@ -14,7 +14,7 @@
{{/tooltip-element}}
</div>
{{#link-to "hosts.new" classNames="btn btn-sm bg-primary"}}{{t 'hostsPage.index.addHost'}}{{/link-to}}
{{#link-to "hosts.templates" classNames="btn btn-sm bg-primary"}}{{t 'hostsPage.index.hostTemplate'}}{{/link-to}}
</div>
</section>

View File

@ -33,7 +33,7 @@ export default Ember.Route.extend({
if ( this.get('backTo') === 'waiting' ) {
this.transitionTo('authenticated.project.waiting');
} else {
this.transitionTo('hosts.index');
this.transitionTo('hosts.templates');
}
}
},

View File

@ -5,4 +5,4 @@
</h1>
</section>
{{add-host model=model driver=driver hostId=hostId completed=(action 'completed') goBack=(route-action 'goBack')}}
{{add-host allowCustom=false model=model driver=driver hostId=hostId completed=(action 'completed') goBack=(route-action 'goBack') savedHost=(route-action 'savedHost')}}

View File

@ -0,0 +1,12 @@
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
launch(model) {
this.transitionToRoute('hosts.templates.launch', model.id);
},
},
filteredContent: Ember.computed('model', function() {
return this.get('model.content').sortBy('driver', 'name');
}),
});

View File

@ -0,0 +1,11 @@
import Ember from 'ember';
export default Ember.Route.extend({
model(/* params */) {
return this.get('store').findAll('hostTemplate', null, {forceReload: true}).then((templates) => {
//@@TODO possibly redirect to add when no temps exist
return templates;
});
}
});

View File

@ -0,0 +1,47 @@
<section class="header clearfix">
{{#link-to "custom-host" classNames="ml-10 btn btn-sm bg-primary pull-right"}}{{t 'hostTemplatesPage.custom'}}{{/link-to}}
{{#link-to "hosts.new" classNames="btn btn-sm bg-primary pull-right"}}{{t 'hostTemplatesPage.addHost'}}{{/link-to}}
<h1>
{{#link-to "infrastructure-tab"}}{{t 'hostsPage.new.header.linkTo'}}{{/link-to}}
{{t 'hostTemplatesPage.title'}}
</h1>
</section>
<section class="pl-15 pr-15 clearfix">
{{#if filteredContent}}
{{#each filteredContent as |host|}}
{{#catalog-box
model=model
active=(not (eq true 'inactive'))
classNames='cloud-host'
showIcon=false
showDescription=false
as |section|
}}
{{#if (eq section 'header')}}
{{action-menu model=host class="pull-right"}}
<div class="catalog-icon mt-10 {{parse-host-icon host.driver}}"/>
{{else if (eq section 'body')}}
<hr class="m-10" />
<h2>{{host.name}}</h2>
<div>
<div class="details">
{{#if (get (host-public-values host) 'region')}}
<div>
<label for="">{{t 'hostTemplatesPage.templateBox.labels.zone'}}: </label>
{{get (host-public-values host) 'region'}}{{get (host-public-values host) 'zone'}}
</div>
{{/if}}
</div>
</div>
{{else if (eq section 'footer')}}
<button role="button" class="btn bg-primary" {{action 'launch' host}}>{{t 'hostTemplatesPage.templateBox.button'}}</button>
{{/if}}
{{/catalog-box}}
{{/each}}
{{else}}
{{empty-table resource="container" newRoute="hosts.new" newTranslationKey="hostTemplatesPage.addHost"}}
{{/if}}
</section>

View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Controller.extend({
});

View File

@ -0,0 +1,35 @@
import Ember from 'ember';
export default Ember.Route.extend({
model(params/* , transistion */) {
return this.get('store').find('hosttemplate', params.template_id).then((template) => {
return this.get('store').find('machinedriver', null, {forceReload: true}).then((drivers) => {
var driver = drivers.findBy('name', template.driver);
var configId = `${template.driver}Config`;
var config = this.get('store').createRecord(template.publicValues[configId]);
var tmp = {
type: 'host',
hostTemplateId: template.id
};
return {
template: template,
config: config,
host: this.get('store').createRecord(tmp),
driver: driver,
}
});
});
},
actions: {
cancel() {
this.transitionTo('hosts.templates.index');
},
goBack() {
if ( this.get('backTo') === 'waiting' ) {
this.transitionTo('authenticated.project.waiting');
} else {
this.transitionTo('hosts');
}
}
},
});

View File

@ -0,0 +1,7 @@
{{cloud-host-add-or-edit
host=model.host
hostTemplate=model.template
driver=model.driver
cancel=(route-action 'cancel')
goBack=(route-action 'goBack')
}}

View File

@ -3,13 +3,6 @@ import Resource from 'ember-api-store/models/resource';
var HostTemplate = Resource.extend({
type: 'hosttemplate',
actions: {
deactivate: function() {
return this.doAction('deactivate');
},
activate: function() {
return this.doAction('activate');
},
},
availableActions: function() {

View File

@ -111,8 +111,13 @@ Router.map(function() {
this.route('new-stack', {path: '/import-compose', resetNamespace: true});
this.route('custom-host', {path: '/hosts/custom', resetNamespace: true});
this.route('hosts', {path: '/hosts', resetNamespace: true}, function() {
this.route('index', {path: '/'});
this.route('templates', {path: '/templates'}, function() {
this.route('index', {path: '/'});
this.route('launch', {path: '/launch/:template_id'});
});
this.route('container-cloud', {path: '/container-cloud'}, function() {
this.route('index', {path: '/'});
@ -195,9 +200,6 @@ Router.map(function() {
this.route('edit-receiver', {path: '/receiver/:receiver_id'});
});
this.route('host-template', {path: '/host-template'}, function(){
this.route('keys', {path: '/keys'});
});
// End: Authenticated
});
});

View File

@ -59,7 +59,7 @@ $lines-to-show: 4;
}
&.cloud-host {
@extend .machine;
height: 300px;
height: 250px;
.help-text {
color: $accent-two;
}

View File

@ -3,11 +3,8 @@
</div>
<div class="row">
<div class="col span-2 col-inline">
<label>{{t 'hostPartial.host.addOptions.labels'}}</label>
</div>
<div class="col span-10">
{{form-user-labels initialLabels=model.labels setLabels=(action 'setLabels')}}
<div class="col span-12">
{{form-user-labels initialLabels=model.labels setLabels=(action 'setLabels') expandAll=null}}
</div>
</div>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.region}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.instanceType}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.size'}}</label>
{{hostOptions.systemDiskSize}}
</div>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.instanceType}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.region}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.storage'}}</label>
{{hostOptions.rootSize}}
</div>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.location}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.env'}}</label>
{{hostOptions.environment}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.size'}}</label>
{{hostOptions.size}}
</div>

View File

@ -0,0 +1,9 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.size}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.region}}
</div>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.availabilityZone}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.instanceProfile}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.size'}}</label>
{{hostOptions.diskSize}}
</div>

View File

@ -0,0 +1,56 @@
<div class="hosts-cloud-add">
<section class="header clearfix">
<div class="row">
<div class="mb-0">
<h1>
{{t 'hostsPage.cloudHostsPage.addPage.header'}}
</h1>
</div>
</div>
</section>
<section class="mt-20">
<form>
<section class="horizontal-form">
<div class="row addtl-info">
<div class="col span-4">
<div class="nav-boxes driver">
{{#if driver.hasUi}}
<div class="nav-box-item driver machine-driver active {{parse-host-icon hostTemplate.driver}}"></div>
{{else}}
<div class="nav-box-item driver machine-driver active other"></div>
{{/if}}
</div>
</div>
<div class="col span-8">
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.template'}}</label>
{{hostTemplate.name}}
</div>
<hr/>
{{#if driver.hasUi}}
{{partial (concat 'host/host-templates/' hostTemplate.driver)}}
{{else}}
{{partial 'host/host-templates/other'}}
{{/if}}
</div>
</div>
<div class="container-fluid">
{{partial "host/add-common"}}
<hr />
<div class="row">
<div class="col span-12">
{{#advanced-section}}
{{form-user-labels initialLabels=clonedModel.labels setLabels=(action 'setLabels') expandAll=null}}
{{/advanced-section}}
</div>
</div>
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel" createLabel='hostsPage.cloudHostsPage.addPage.launch'}}
</section>
</form>
</section>
</div>

View File

@ -0,0 +1,5 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.driver'}}</label>
{{hostTemplate.driver}}
</div>
<hr/>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.facilityCode}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.plan}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.os'}}</label>
{{hostOptions.os}}
</div>

View File

@ -0,0 +1,9 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.region}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.flavorId}}
</div>

View File

@ -0,0 +1,14 @@
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.zone'}}</label>
{{hostOptions.datacenter}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.instance'}}</label>
{{hostOptions.vcenter}}
</div>
<hr/>
<div>
<label for="">{{t 'hostsPage.cloudHostsPage.addPage.size'}}</label>
{{hostOptions.diskSize}}
</div>

View File

@ -211,13 +211,6 @@ const navTree = [
route: 'authenticated.project.hooks',
ctx: [getProjectId],
},
{
id: 'infra-template-keys',
localizedLabel: 'nav.infra.templateKeys',
icon: 'icon icon-key',
route: 'authenticated.project.host-template.keys',
ctx: [getProjectId],
},
],
},

View File

@ -697,6 +697,11 @@ hostsPage:
storage: 'Storage:'
transfer: 'Transfer:'
zone: 'Zone:'
env: 'Environment:'
size: 'Size:'
os: 'OS:'
driver: 'Driver:'
template: 'Template Name:'
tabs:
fav: Favorites
browse: Browse
@ -735,6 +740,7 @@ hostsPage:
index:
header: Hosts
addHost: Add Host
hostTemplate: Host Templates
tooltip:
listView: List
iconView: State Icons
@ -842,6 +848,14 @@ hostsPage:
noData: This host does not have any volumes
hostTemplatesPage:
title: Templates
addHost: Add Host Template
custom: Add Custom Host
templateBox:
button: Launch
labels:
region: Region
zone: Zone
keys:
header: Host Template Keys
buttonText: New Key
@ -2767,6 +2781,7 @@ machine:
securityGroupSection: Security Group
securityGroup:
label: Security Group
choose: Choose an existing group
defaultExisting: "Standard: Use the existing <code>{groupName}</code> group"
defaultCreate: "Standard: Automatically create a <code>{groupName}</code> group"
custom: "Custom: Choose an existing group"
@ -2814,6 +2829,7 @@ machine:
label: Subscription Cert
placeholder: Your Azure subscription certificate
instanceSection: Instance
instanceOptionsSection: Instance Options
image:
label: Image
placeholder: 'canonical:UbuntuServer:16.04.0-LTS:latest'
@ -2908,6 +2924,7 @@ machine:
A Personal Access Token from the DigitalOcean
<a href="https://cloud.digitalocean.com/settings/applications" target="_blank">Apps & API</a> screen
instanceSection: Instance
instanceOptionsSection: Instance Options
image:
label: Image
sshUser:
@ -2957,6 +2974,7 @@ machine:
selectSecurityGroupAction: "Next: Set Instance options"
loadingInstance: Fetching available Instance settings...
instanceSection: Instance
instanceOptionsSection: Instance Options
instanceProfile:
label: Instance Profile
diskSize:
@ -2971,6 +2989,8 @@ machine:
driver:
label: Driver
optionsSection: "{driverName} Options"
instanceSection: Instance
instanceOptionsSection: Instance Options
driverPacket:
accountSection: Account Access
@ -2982,6 +3002,7 @@ machine:
placeholder: Your Packet API key
apiKeyHelp: From the Packet <a href="https://app.packet.net/portal#/api-keys" target="_blank">API Keys</a> screen
instanceSection: Instance
instanceOptionsSection: Instance Options
image:
label: Image
size:
@ -3003,6 +3024,7 @@ machine:
region:
label: Region
instanceSection: Instance
instanceOptionsSection: Instance Options
flavor:
label: Flavor
@ -3022,6 +3044,7 @@ machine:
loginAction: "Next: Authenticate & Create a New Cloud Instance"
loadingInstance: Loading cloud instance creation details...
instanceSection: Instance
instanceOptionsSection: Instance Options
regionSection: Region
region:
label: Region
@ -3042,6 +3065,7 @@ machine:
password:
label: Password
instanceSection: Instance
instanceOptionsSection: Instance Options
cpuCount:
label: CPUs
memorySize:
@ -3078,6 +3102,7 @@ machine:
label: Api Endpoint
placeholder: Private Aliyun Api Server Endpoint
instanceSection: Instance Section
instanceOptionsSection: Instance Options Section
instanceDescription:
label: Instance Description
placeholder: Instance Description