mirror of https://github.com/rancher/ui.git
Merge pull request #2640 from westlywright/cloud-keys
cloud credentials
This commit is contained in:
commit
542b348f75
|
|
@ -1,12 +1,20 @@
|
|||
import { get } from '@ember/object';
|
||||
|
||||
export function initialize(application) {
|
||||
// Monkey patch AWS SDK to go through our proxy
|
||||
var orig = AWS.XHRClient.prototype.handleRequest;
|
||||
|
||||
AWS.XHRClient.prototype.handleRequest = function handleRequest(httpRequest, httpOptions, callback, errCallback) {
|
||||
httpRequest.endpoint.protocol = 'http:';
|
||||
httpRequest.endpoint.port = 80;
|
||||
httpRequest.headers['X-Api-Headers-Restrict'] = 'Content-Length';
|
||||
httpRequest.headers['X-Api-Auth-Header'] = httpRequest.headers['Authorization'];
|
||||
|
||||
if (get(httpOptions, 'cloudCredentialId')) {
|
||||
httpRequest.headers['X-Api-CattleAuth-Header'] = `awsv4 credID=${ get(httpOptions, 'cloudCredentialId') }`;
|
||||
} else {
|
||||
httpRequest.endpoint.protocol = 'http:';
|
||||
httpRequest.endpoint.port = 80;
|
||||
httpRequest.headers['X-Api-Auth-Header'] = httpRequest.headers['Authorization'];
|
||||
}
|
||||
|
||||
delete httpRequest.headers['Authorization'];
|
||||
httpRequest.headers['Content-Type'] = `rancher:${ httpRequest.headers['Content-Type'] }`;
|
||||
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ const rootNav = [
|
|||
{
|
||||
id: 'global-security-roles',
|
||||
localizedLabel: 'nav.admin.security.roles',
|
||||
icon: 'icon icon-key',
|
||||
icon: 'icon icon-users',
|
||||
route: 'global-admin.security.roles',
|
||||
resource: ['roletemplate'],
|
||||
resourceScope: 'global',
|
||||
|
|
@ -366,6 +366,14 @@ const rootNav = [
|
|||
resource: ['podsecuritypolicytemplate'],
|
||||
resourceScope: 'global',
|
||||
},
|
||||
{
|
||||
id: 'global-security-cloud-keys',
|
||||
localizedLabel: 'nav.admin.security.cloudKeys',
|
||||
icon: 'icon icon-secrets',
|
||||
route: 'global-admin.security.cloud-keys',
|
||||
resource: ['cloudcredential'],
|
||||
resourceScope: 'global',
|
||||
},
|
||||
{
|
||||
id: 'global-security-authentication',
|
||||
localizedLabel: 'nav.admin.security.authentication',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import Resource from '@rancher/ember-api-store/models/resource';
|
||||
import { computed } from '@ember/object';
|
||||
import { notEmpty } from '@ember/object/computed';
|
||||
|
||||
const cloudCredential = Resource.extend({
|
||||
type: 'cloudCredential',
|
||||
|
||||
canClone: false,
|
||||
canEdit: false,
|
||||
|
||||
isAmazon: notEmpty('amazonec2credentialConfig'),
|
||||
isAzure: notEmpty('azurecredentialConfig'),
|
||||
isDo: notEmpty('digitaloceancredentialConfig'),
|
||||
isVMware: notEmpty('vmwarevspherecredentialConfig'),
|
||||
|
||||
displayType: computed('amazonec2credentialConfig', 'azurecredentialConfig', 'digitaloceancredentialConfig', 'vmwarevspherecredentialConfig', function() {
|
||||
const {
|
||||
isAmazon,
|
||||
isAzure,
|
||||
isDo,
|
||||
isVMware
|
||||
} = this;
|
||||
|
||||
if (isAmazon) {
|
||||
return 'Amazon';
|
||||
} else if (isAzure) {
|
||||
return 'Azure';
|
||||
} else if (isDo) {
|
||||
return 'Digital Ocean';
|
||||
} else if (isVMware) {
|
||||
return 'VMware vSphere';
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
});
|
||||
|
||||
export default cloudCredential;
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import Component from '@ember/component';
|
||||
import NewOrEdit from 'shared/mixins/new-or-edit';
|
||||
import layout from './template';
|
||||
import { get, set, computed } from '@ember/object';
|
||||
import { next } from '@ember/runloop';
|
||||
|
||||
const CRED_CONFIG_CHOICES = [
|
||||
{
|
||||
name: 'amazon',
|
||||
displayName: 'Amazon',
|
||||
driver: 'amazonec2',
|
||||
configField: 'amazonec2credentialConfig',
|
||||
},
|
||||
{
|
||||
name: 'azure',
|
||||
displayName: 'Azure',
|
||||
driver: 'azure',
|
||||
configField: 'azurecredentialConfig',
|
||||
},
|
||||
{
|
||||
name: 'digitalOcean',
|
||||
displayName: 'Digital Ocean',
|
||||
driver: 'digitalocean',
|
||||
configField: 'digitaloceancredentialConfig',
|
||||
},
|
||||
{
|
||||
name: 'vmware',
|
||||
displayName: 'VMware vSphere',
|
||||
driver: 'vmwarevsphere',
|
||||
configField: 'vmwarevspherecredentialConfig',
|
||||
},
|
||||
]
|
||||
|
||||
export default Component.extend(NewOrEdit, {
|
||||
globalStore: service(),
|
||||
layout,
|
||||
nodeConfigTemplateType: null,
|
||||
cloudKeyType: null,
|
||||
model: null,
|
||||
cancelAdd: null,
|
||||
doneSavingCloudCredential: null,
|
||||
disableHeader: false,
|
||||
|
||||
didReceiveAttrs() {
|
||||
set(this, 'model', this.globalStore.createRecord({ type: 'cloudCredential' }));
|
||||
},
|
||||
|
||||
actions: {
|
||||
selectConfig(configType) {
|
||||
this.cleanupPreviousConfig();
|
||||
|
||||
set(this, 'cloudKeyType', configType);
|
||||
|
||||
this.initCloudCredentialConfig();
|
||||
},
|
||||
},
|
||||
|
||||
config: computed('cloudKeyType', {
|
||||
get() {
|
||||
const { model } = this;
|
||||
const type = this.getConfigField();
|
||||
|
||||
return get(model, type);
|
||||
}
|
||||
}),
|
||||
|
||||
configChoices: computed('driverName', function() {
|
||||
if (get(this, 'driverName')) {
|
||||
const { driverName } = this;
|
||||
|
||||
let match = CRED_CONFIG_CHOICES.findBy('driver', driverName);
|
||||
|
||||
|
||||
next(() => {
|
||||
set(this, 'cloudKeyType', get(match, 'name'));
|
||||
this.initCloudCredentialConfig();
|
||||
})
|
||||
|
||||
return [match];
|
||||
} else {
|
||||
return CRED_CONFIG_CHOICES.sortBy('displayName');
|
||||
}
|
||||
}),
|
||||
|
||||
saveDisabled: computed('config.{amazonec2credentialConfig,azurecredentialConfig,digitaloceancredentialConfig,vmwarevspherecredentialConfig}', 'cloudKeyType', function() {
|
||||
if (this.getConfigField()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
initCloudCredentialConfig() {
|
||||
const { model } = this;
|
||||
const type = this.getConfigField();
|
||||
|
||||
set(model, type, this.globalStore.createRecord({ type: type.toLowerCase() }));
|
||||
},
|
||||
|
||||
doneSaving(neu) {
|
||||
this.doneSavingCloudCredential(neu);
|
||||
},
|
||||
|
||||
cleanupPreviousConfig() {
|
||||
const { model } = this;
|
||||
const configField = this.getConfigField();
|
||||
|
||||
if (configField) {
|
||||
delete model[configField];
|
||||
}
|
||||
},
|
||||
|
||||
getConfigField() {
|
||||
const { cloudKeyType, configChoices } = this;
|
||||
|
||||
if (cloudKeyType) {
|
||||
const matchType = configChoices.findBy('name', cloudKeyType);
|
||||
|
||||
return get(matchType, 'configField');
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
parseNodeTemplateConfigType(nodeTemplate) {
|
||||
return Object.keys(nodeTemplate).find((f) => f.toLowerCase().indexOf('config') > -1);
|
||||
},
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
<section class="horizontal-form container-fluid">
|
||||
{{#unless disableHeader}}
|
||||
<h2>
|
||||
{{t "modalAddCloudKey.header"}}
|
||||
</h2>
|
||||
{{/unless}}
|
||||
<hr/>
|
||||
|
||||
{{form-name-description
|
||||
model=primaryResource
|
||||
namePlaceholder="newSecret.name.placeholder"
|
||||
descriptionPlaceholder="newSecret.description.placeholder"
|
||||
}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "modalAddCloudKey.type"}}
|
||||
</label>
|
||||
|
||||
<select
|
||||
class="form-control"
|
||||
onchange={{action "selectConfig" value="target.value"}}
|
||||
>
|
||||
{{#if (not-eq cloudKeyType value)}}
|
||||
<option value="" selected=true >
|
||||
{{t "modalAddCloudKey.typeSelect.prompt"}}
|
||||
</option>
|
||||
{{/if}}
|
||||
{{#each configChoices as |choice|}}
|
||||
<option
|
||||
value="{{choice.name}}"
|
||||
selected={{eq choice.name cloudKeyType}}
|
||||
>
|
||||
{{choice.displayName}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
{{#if (eq cloudKeyType "amazon")}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="amazonec2-accessKey">
|
||||
{{t "modalAddCloudKey.amazonec2.accessKey.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
name="username"
|
||||
classNames="form-control"
|
||||
placeholder=(t "modalAddCloudKey.amazonec2.accessKey.placeholder")
|
||||
value=config.accessKey
|
||||
id="amazonec2-accessKey"
|
||||
}}
|
||||
</div>
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="amazonec2-secretKey">
|
||||
{{t "modalAddCloudKey.amazonec2.secretKey.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="password"
|
||||
name="password"
|
||||
classNames="form-control"
|
||||
placeholder=(t "modalAddCloudKey.amazonec2.secretKey.placeholder")
|
||||
value=config.secretKey
|
||||
id="amazonec2-secretKey"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{else if (eq cloudKeyType "azure")}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.subscriptionId.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.subscriptionId
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.subscriptionId.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="azure-clientId">
|
||||
{{t "modalAddCloudKey.azure.clientId.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.clientId
|
||||
classNames="form-control"
|
||||
id="azure-clientId"
|
||||
placeholder=(t "modalAddCloudKey.azure.clientId.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="azure-clientSecret">
|
||||
{{t "modalAddCloudKey.azure.clientSecret.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="password"
|
||||
value=config.clientSecret
|
||||
classNames="form-control"
|
||||
id="azure-clientSecret"
|
||||
placeholder=(t "modalAddCloudKey.azure.clientSecret.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{else if (eq cloudKeyType "digitalOcean")}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="digitalocean-accessToken">
|
||||
{{t "modalAddCloudKey.digitalocean.accessToken.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="password"
|
||||
value=config.accessToken
|
||||
classNames="form-control"
|
||||
placeholder=(t "modalAddCloudKey.digitalocean.accessToken.placeholder")
|
||||
id="digitalocean-accessToken"
|
||||
}}
|
||||
<p class="text-info">
|
||||
{{t "modalAddCloudKey.digitalocean.accessToken.help" htmlSafe=true}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{else if (eq cloudKeyType "vmware")}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.vmwarevsphere.vcenter.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
class="form-control"
|
||||
value=config.vcenter
|
||||
placeholder=(t "nodeDriver.vmwarevsphere.vcenter.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.vmwarevsphere.vcenterPort.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input-integer
|
||||
min=1
|
||||
max=65535
|
||||
class="form-control"
|
||||
value=config.vcenterPort
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.vmwarevsphere.username.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.username
|
||||
classNames="form-control"
|
||||
}}
|
||||
</div>
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.vmwarevsphere.password.label"}}{{field-required}}
|
||||
</label>
|
||||
{{input
|
||||
type="password"
|
||||
value=config.password
|
||||
classNames="form-control"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">{{t "nodeDriver.vmwarevsphere.access.help"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="footer-actions">
|
||||
{{save-cancel
|
||||
saveDisabled=saveDisabled
|
||||
save="save"
|
||||
cancel=cancelAdd
|
||||
}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import Component from '@ember/component';
|
||||
import ModalBase from 'shared/mixins/modal-base';
|
||||
import layout from './template';
|
||||
|
||||
export default Component.extend(ModalBase, {
|
||||
layout,
|
||||
classNames: ['large-modal', 'alert'],
|
||||
});
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{{cru-cloud-credential
|
||||
doneSavingCloudCredential=(action "close")
|
||||
cancelAdd=(action "cancel")
|
||||
}}
|
||||
|
|
@ -69,5 +69,9 @@ export default buildRoutes(function() {
|
|||
this.route('okta');
|
||||
this.route('freeipa');
|
||||
});
|
||||
|
||||
this.route('cloud-keys', function() {
|
||||
this.route('index', { path: '/' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import Controller from '@ember/controller';
|
||||
import { computed, get } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import layout from './template';
|
||||
|
||||
const HEADERS = [
|
||||
{
|
||||
name: 'type',
|
||||
sort: ['displayType'],
|
||||
searchField: 'displayType',
|
||||
translationKey: 'generic.type',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['displayName'],
|
||||
searchField: 'displayName',
|
||||
translationKey: 'generic.name',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
classNames: 'text-right pr-20',
|
||||
name: 'created',
|
||||
sort: ['created'],
|
||||
translationKey: 'generic.created',
|
||||
},
|
||||
];
|
||||
|
||||
export default Controller.extend({
|
||||
modal: service(),
|
||||
|
||||
layout,
|
||||
sortBy: 'created',
|
||||
searchText: '',
|
||||
headers: HEADERS,
|
||||
|
||||
actions: {
|
||||
addCloudKey() {
|
||||
this.modal.toggleModal('modal-add-cloud-key');
|
||||
}
|
||||
},
|
||||
|
||||
filteredContent: computed('model.@each.{id}', function() {
|
||||
return get(this, 'model').sortBy('id');
|
||||
}),
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
// import { get } from '@ember/object';
|
||||
|
||||
export default Route.extend({
|
||||
globalStore: service(),
|
||||
|
||||
model(/* params */) {
|
||||
return this.globalStore.findAll('cloudcredential');
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<section class="header has-tabs clearfix p-0">
|
||||
<div class="right-buttons">
|
||||
<button
|
||||
{{action "addCloudKey"}}
|
||||
class="btn btn-sm bg-primary right-divider-btn"
|
||||
disabled={{rbac-prevents resource="cloudcredential" scope="global" permission="create"}}
|
||||
>
|
||||
{{t "cloudKeysPage.addKey"}}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="instances">
|
||||
{{#sortable-table
|
||||
bulkActions=true
|
||||
classNames="grid sortable-table"
|
||||
sortBy=sortBy
|
||||
descending=descending
|
||||
headers=headers
|
||||
searchText=searchText
|
||||
showHeader=true
|
||||
body=filteredContent
|
||||
rightActions=true
|
||||
as |sortable kind row dt|
|
||||
}}
|
||||
{{#if (eq kind "row")}}
|
||||
<tr class="main-row">
|
||||
<td valign="middle" class="row-check" style="padding-top: 2px;">
|
||||
{{check-box nodeId=row.id}}
|
||||
</td>
|
||||
<td data-title="{{t "generic.type"}}:" class="clip">
|
||||
{{row.displayType}}
|
||||
</td>
|
||||
<td data-title="{{t "generic.name"}}:" class="clip">
|
||||
{{row.displayName}}
|
||||
</td>
|
||||
<td data-title="{{t "generic.created"}}:" class="text-right pr-20">
|
||||
{{date-calendar row.created}}
|
||||
</td>
|
||||
<td data-title="{{t "generic.actions"}}:" class="actions">
|
||||
{{action-menu model=row}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<td
|
||||
colspan="5"
|
||||
class="text-center text-muted lacsso pt-20 pb-20"
|
||||
>
|
||||
{{t "cloudKeysPage.index.table.noMatch"}}
|
||||
</td>
|
||||
{{else if (eq kind "norows")}}
|
||||
<td
|
||||
colspan="5"
|
||||
class="text-center text-muted lacsso pt-20 pb-20"
|
||||
>
|
||||
{{t "cloudKeysPage.index.table.noData"}}
|
||||
</td>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
</section>
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'global-admin/components/cru-cloud-credential/component';
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'global-admin/components/modal-add-cloud-key/component';
|
||||
|
|
@ -9,6 +9,7 @@ import Component from '@ember/component';
|
|||
import NodeDriver from 'shared/mixins/node-driver';
|
||||
import layout from './template';
|
||||
import { INSTANCE_TYPES, nameFromResource, tagsFromResource, REGIONS } from 'shared/utils/amazon';
|
||||
import { randomStr } from 'shared/utils/util';
|
||||
|
||||
let RANCHER_GROUP = 'rancher-nodes';
|
||||
|
||||
|
|
@ -84,21 +85,28 @@ export default Component.extend(NodeDriver, {
|
|||
},
|
||||
|
||||
actions: {
|
||||
finishAndSelectCloudCredential(cred) {
|
||||
if (cred) {
|
||||
set(this, 'primaryResource.cloudCredentialId', get(cred, 'id'));
|
||||
|
||||
this.send('awsLogin');
|
||||
}
|
||||
},
|
||||
|
||||
awsLogin(cb) {
|
||||
let self = this;
|
||||
|
||||
setProperties(this, {
|
||||
'errors': null,
|
||||
'config.accessKey': (get(this, 'config.accessKey') || '').trim(),
|
||||
'config.secretKey': (get(this, 'config.secretKey') || '').trim(),
|
||||
});
|
||||
set(this, 'errors', null);
|
||||
|
||||
let subnets = [];
|
||||
let rName = get(this, 'config.region');
|
||||
|
||||
// have to have something in there before we describe the request even though we are going to replace with the actual cred id
|
||||
let ec2 = new AWS.EC2({
|
||||
accessKeyId: get(this, 'config.accessKey'),
|
||||
secretAccessKey: get(this, 'config.secretKey'),
|
||||
region: rName,
|
||||
accessKeyId: randomStr(),
|
||||
secretAccessKey: randomStr(),
|
||||
region: rName,
|
||||
httpOptions: { cloudCredentialId: get(this, 'model.cloudCredentialId') },
|
||||
});
|
||||
|
||||
let vpcNames = {};
|
||||
|
|
@ -110,7 +118,9 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
errors.pushObject(err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -126,7 +136,9 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
errors.pushObject(err);
|
||||
set(this, 'errors', errors);
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -154,7 +166,9 @@ export default Component.extend(NodeDriver, {
|
|||
'allSubnets': subnets,
|
||||
'step': 2,
|
||||
});
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
@ -164,14 +178,18 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
if ( !get(this, 'selectedZone') ) {
|
||||
set(this, 'errors', ['Select an Availability Zone']);
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !get(this, 'selectedSubnet') ) {
|
||||
set(this, 'errors', ['Select a VPC or Subnet']);
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -185,7 +203,9 @@ export default Component.extend(NodeDriver, {
|
|||
ec2.describeSecurityGroups({ Filters: [filter] }, (err, data) => {
|
||||
if ( err ) {
|
||||
set(this, 'errors', [err]);
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -242,7 +262,9 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
setProperties(this, { step: 4, });
|
||||
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -257,11 +279,12 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
set(this, 'config.tags', array.join(','));
|
||||
}),
|
||||
stepDidChange: function() {
|
||||
|
||||
stepDidChange: observer('context.step', function() {
|
||||
scheduleOnce('afterRender', this, () => {
|
||||
document.body.scrollTop = document.body.scrollHeight;
|
||||
});
|
||||
}.observes('context.step'),
|
||||
}),
|
||||
|
||||
selectedZone: computed('config.{region,zone}', {
|
||||
get() {
|
||||
|
|
@ -301,7 +324,7 @@ export default Component.extend(NodeDriver, {
|
|||
}
|
||||
}),
|
||||
|
||||
zoneChoices: function() {
|
||||
zoneChoices: computed('allSubnets.@each.{zone}', function() {
|
||||
const choices = (get(this, 'allSubnets') || []).map((subnet) => {
|
||||
return get(subnet, 'zone');
|
||||
}).sort().uniq();
|
||||
|
|
@ -315,9 +338,9 @@ export default Component.extend(NodeDriver, {
|
|||
}
|
||||
|
||||
return choices;
|
||||
}.property('allSubnets.@each.{zone}'),
|
||||
}),
|
||||
|
||||
subnetChoices: function() {
|
||||
subnetChoices: computed('selectedZone', 'allSubnets.@each.{subnetId,vpcId,zone}', function() {
|
||||
let out = [];
|
||||
let seenVpcs = [];
|
||||
|
||||
|
|
@ -350,7 +373,7 @@ export default Component.extend(NodeDriver, {
|
|||
});
|
||||
|
||||
return out.sortBy('sortKey');
|
||||
}.property('selectedZone', 'allSubnets.@each.{subnetId,vpcId,zone}'),
|
||||
}),
|
||||
|
||||
selectedSubnet: computed('config.{subnetId,vpcId}', {
|
||||
set(key, val) {
|
||||
|
|
@ -390,7 +413,6 @@ export default Component.extend(NodeDriver, {
|
|||
}),
|
||||
|
||||
bootstrap() {
|
||||
let pref = get(this, 'prefs.amazonec2') || {};
|
||||
let config = get(this, 'globalStore').createRecord({
|
||||
type: 'amazonec2Config',
|
||||
region: 'us-west-2',
|
||||
|
|
@ -398,8 +420,6 @@ export default Component.extend(NodeDriver, {
|
|||
securityGroup: '',
|
||||
zone: 'a',
|
||||
rootSize: '16',
|
||||
accessKey: pref.accessKey || '',
|
||||
secretKey: pref.secretKey || '',
|
||||
});
|
||||
|
||||
set(this, 'model.amazonec2Config', config);
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
<div class="over-hr"><span>{{driverOptionsTitle}}</span></div>
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.amazonec2.access.title')
|
||||
detail=(t 'nodeDriver.amazonec2.access.detail')
|
||||
title=(t "nodeDriver.amazonec2.access.title")
|
||||
detail=(t "nodeDriver.amazonec2.access.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-4">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.region.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.region.label"}}</label>
|
||||
{{#if (eq step 1)}}
|
||||
<select class="form-control" onchange={{action (mut config.region) value="target.value"}}>
|
||||
{{#each regionChoices as |choice|}}
|
||||
|
|
@ -22,55 +22,49 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="col span-4">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.accessKey.label'}}</label>
|
||||
{{#if (eq step 1)}}
|
||||
{{input type="text" name="username" classNames="form-control" placeholder=(t 'nodeDriver.amazonec2.accessKey.placeholder') value=config.accessKey}}
|
||||
{{else}}
|
||||
<div>{{config.accessKey}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="col span-4">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.secretKey.label'}}</label>
|
||||
{{#if (eq step 1)}}
|
||||
{{input type="password" name="password" classNames="form-control" placeholder=(t 'nodeDriver.amazonec2.secretKey.placeholder') value=config.secretKey}}
|
||||
{{else}}
|
||||
<div class="text-muted text-italic">{{t 'nodeDriver.amazonec2.secretKey.provided'}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if (eq step 1)}}
|
||||
{{form-auth-cloud-credential
|
||||
driverName=driverName
|
||||
errors=errros
|
||||
primaryResource=primaryResource
|
||||
cloudCredentials=cloudCredentials
|
||||
finishAndSelectCloudCredential=(action "finishAndSelectCloudCredential")
|
||||
progressStep=(action "awsLogin")
|
||||
cancel=(action "cancel")
|
||||
}}
|
||||
{{else}}
|
||||
<div class="row">
|
||||
<div class="col span-4">
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.accessKey.label"}}</label>
|
||||
<div>{{config.accessKey}}</div>
|
||||
</div>
|
||||
|
||||
<div class="col span-4">
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.secretKey.label"}}</label>
|
||||
<div class="text-muted text-italic">{{t "nodeDriver.amazonec2.secretKey.provided"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span-8 offset-4">
|
||||
<p class="text-info text-small m-0">{{t 'nodeDriver.amazonec2.access.help'}}</p>
|
||||
<p class="text-info text-small m-0">{{t "nodeDriver.amazonec2.access.help"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{top-errors errors=errors}}
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#if (eq step 1)}}
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel
|
||||
save="awsLogin"
|
||||
cancel="cancel"
|
||||
createLabel="nodeDriver.amazonec2.access.next"
|
||||
savingLabel="nodeDriver.amazonec2.access.loading"
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
<div class="{{unless (gte step 2) 'hide'}}">
|
||||
<div class="{{unless (gte step 2) "hide"}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.amazonec2.zone.title')
|
||||
detail=(t 'nodeDriver.amazonec2.zone.detail')
|
||||
title=(t "nodeDriver.amazonec2.zone.title")
|
||||
detail=(t "nodeDriver.amazonec2.zone.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{#if (eq step 2)}}
|
||||
<div class="row">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.availabilityZone'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.availabilityZone"}}</label>
|
||||
<select class="form-control" onchange={{action (mut selectedZone) value="target.value"}}>
|
||||
{{#each zoneChoices as |choice|}}
|
||||
<option value={{choice}} selected={{eq selectedZone choice}}>{{choice}}</option>
|
||||
|
|
@ -79,7 +73,7 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label class="acc-label pt-20">{{t 'nodeDriver.amazonec2.subnet'}}</label>
|
||||
<label class="acc-label pt-20">{{t "nodeDriver.amazonec2.subnet"}}</label>
|
||||
{{#if subnetChoices.length}}
|
||||
{{#each subnetChoices as |choice|}}
|
||||
{{#if choice.isVpc}}
|
||||
|
|
@ -115,11 +109,11 @@
|
|||
{{else}}
|
||||
<div class="row">
|
||||
<div class="span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.availabilityZone'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.availabilityZone"}}</label>
|
||||
{{config.region}}{{config.zone}}
|
||||
</div>
|
||||
<div class="span-6">
|
||||
<label class="acc-label pt-20">{{t 'nodeDriver.amazonec2.subnet'}}</label>
|
||||
<label class="acc-label pt-20">{{t "nodeDriver.amazonec2.subnet"}}</label>
|
||||
{{#if config.subnetId}}
|
||||
{{config.subnetId}}
|
||||
{{else}}
|
||||
|
|
@ -141,10 +135,10 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="{{unless (gte step 3) 'hide'}}">
|
||||
<div class="{{unless (gte step 3) "hide"}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.amazonec2.securityGroup.title')
|
||||
detail=(t 'nodeDriver.amazonec2.securityGroup.detail')
|
||||
title=(t "nodeDriver.amazonec2.securityGroup.title")
|
||||
detail=(t "nodeDriver.amazonec2.securityGroup.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
|
|
@ -154,23 +148,23 @@
|
|||
<div class="radio pt-10">
|
||||
<label>
|
||||
{{radio-button selection=whichSecurityGroup value="default"}}
|
||||
{{t 'nodeDriver.amazonec2.securityGroup.defaultCreate' groupName=defaultSecurityGroupName htmlSafe=true}}
|
||||
{{t "nodeDriver.amazonec2.securityGroup.defaultCreate" groupName=defaultSecurityGroupName htmlSafe=true}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{{#if (and settings.isRancher (not isCustomSecurityGroup))}}
|
||||
<p class="text-info ml-20"><a href="{{settings.docsBase}}/installation/references/" target="_blank">{{t 'nodeDriver.amazonec2.portHelp.link'}}</a> {{t 'nodeDriver.amazonec2.portHelp.text'}}</p>
|
||||
<p class="text-info ml-20"><a href="{{settings.docsBase}}/installation/references/" target="_blank">{{t "nodeDriver.amazonec2.portHelp.link"}}</a> {{t "nodeDriver.amazonec2.portHelp.text"}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="radio pt-10">
|
||||
<label>
|
||||
{{radio-button selection=whichSecurityGroup value="custom"}}
|
||||
{{t 'nodeDriver.amazonec2.securityGroup.choose'}}
|
||||
{{t "nodeDriver.amazonec2.securityGroup.choose"}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{{#if isCustomSecurityGroup}}
|
||||
<select class="form-control existing-security-groups" multiple="true" onchange={{action 'multiSecurityGroupSelect' ''}}>
|
||||
<select class="form-control existing-security-groups" multiple="true" onchange={{action "multiSecurityGroupSelect" ""}}>
|
||||
{{#each allSecurityGroups as |choice|}}
|
||||
<option value={{choice.name}} selected={{array-includes selectedSecurityGroup choice.name}}>{{choice.name}} ({{choice.id}})</option>
|
||||
{{/each}}
|
||||
|
|
@ -203,17 +197,17 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="{{unless (gte step 4) 'hide'}}">
|
||||
<div class="{{unless (gte step 4) "hide"}}">
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.amazonec2.instance.title')
|
||||
detail=(t 'nodeDriver.amazonec2.instance.detail')
|
||||
title=(t "nodeDriver.amazonec2.instance.title")
|
||||
detail=(t "nodeDriver.amazonec2.instance.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.instanceType.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.instanceType.label"}}</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
value=config.instanceType
|
||||
|
|
@ -225,59 +219,59 @@
|
|||
</div>
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.rootSize.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.rootSize.label"}}</label>
|
||||
<div class="input-group">
|
||||
{{input type="text" classNames="form-control" placeholder="" value=config.rootSize}}
|
||||
<span class="input-group-addon bg-default">{{t 'nodeDriver.amazonec2.rootSize.unit'}}</span>
|
||||
<span class="input-group-addon bg-default">{{t "nodeDriver.amazonec2.rootSize.unit"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.ami.label'}}</label>
|
||||
{{input type="text" classNames="form-control" placeholder=(t 'nodeDriver.amazonec2.ami.placeholder') value=config.ami}}
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.ami.label"}}</label>
|
||||
{{input type="text" classNames="form-control" placeholder=(t "nodeDriver.amazonec2.ami.placeholder") value=config.ami}}
|
||||
{{#if settings.isRancher}}
|
||||
<p class="help-block">
|
||||
<a href="https://github.com/rancher/os/blob/master/README.md/#user-content-amazon" target="_blank">{{t 'nodeDriver.amazonec2.ami.rancherList'}}</a>
|
||||
<a href="https://github.com/rancher/os/blob/master/README.md/#user-content-amazon" target="_blank">{{t "nodeDriver.amazonec2.ami.rancherList"}}</a>
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.sshUser.label'}}</label>
|
||||
{{input type="text" classNames="form-control" placeholder=(t 'nodeDriver.amazonec2.sshUser.placeholder') value=config.sshUser}}
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.sshUser.label"}}</label>
|
||||
{{input type="text" classNames="form-control" placeholder=(t "nodeDriver.amazonec2.sshUser.placeholder") value=config.sshUser}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.iam.label'}}</label>
|
||||
{{input type="text" classNames="form-control" value=config.iamInstanceProfile placeholder=(t 'nodeDriver.amazonec2.iam.placeholder')}}
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.iam.label"}}</label>
|
||||
{{input type="text" classNames="form-control" value=config.iamInstanceProfile placeholder=(t "nodeDriver.amazonec2.iam.placeholder")}}
|
||||
</div>
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.privateIp.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.privateIp.label"}}</label>
|
||||
<div class="checkbox">
|
||||
<label class="acc-label">{{input type="checkbox" checked=config.privateAddressOnly}} {{t 'nodeDriver.amazonec2.onlyPrivate.label'}}</label>
|
||||
<label class="acc-label">{{input type="checkbox" checked=config.privateAddressOnly}} {{t "nodeDriver.amazonec2.onlyPrivate.label"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.requestSpotInstance.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.requestSpotInstance.label"}}</label>
|
||||
<div class="checkbox">
|
||||
<label class="acc-label">{{input type="checkbox" checked=config.requestSpotInstance}} {{t 'nodeDriver.amazonec2.requestSpotInstance.enable'}}</label>
|
||||
<label class="acc-label">{{input type="checkbox" checked=config.requestSpotInstance}} {{t "nodeDriver.amazonec2.requestSpotInstance.enable"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if config.requestSpotInstance}}
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.amazonec2.spotPrice.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.amazonec2.spotPrice.label"}}</label>
|
||||
<div class="input-group">
|
||||
{{input type="text" classNames="form-control" placeholder="" value=config.spotPrice}}
|
||||
<span class="input-group-addon bg-default">{{t 'nodeDriver.amazonec2.spotPrice.unit'}}</span>
|
||||
<span class="input-group-addon bg-default">{{t "nodeDriver.amazonec2.spotPrice.unit"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
@ -303,7 +297,7 @@
|
|||
|
||||
{{form-user-labels
|
||||
initialLabels=labelResource.labels
|
||||
setLabels=(action 'setLabels')
|
||||
setLabels=(action "setLabels")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ export default Component.extend(NodeDriver, {
|
|||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
finishAndSelectCloudCredential(credential) {
|
||||
set(this, 'model.cloudCredentialId', get(credential, 'id'))
|
||||
}
|
||||
},
|
||||
|
||||
evironmentChoiceObserver: observer('config.environment', function() {
|
||||
let environment = get(this, 'config.environment');
|
||||
|
||||
|
|
@ -116,8 +122,6 @@ export default Component.extend(NodeDriver, {
|
|||
let config = get(this, 'globalStore').createRecord({
|
||||
type: CONFIG,
|
||||
subscriptionId: '',
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
openPort: ['6443/tcp', '2379/tcp', '2380/tcp', '8472/udp', '4789/udp', '10256/tcp', '10250/tcp', '10251/tcp', '10252/tcp'],
|
||||
});
|
||||
|
||||
|
|
@ -146,18 +150,6 @@ export default Component.extend(NodeDriver, {
|
|||
errors.push('Name is required');
|
||||
}
|
||||
|
||||
if (!get(this, 'config.subscriptionId')) {
|
||||
errors.push('Subscription ID is required');
|
||||
}
|
||||
|
||||
if (!get(this, 'config.clientId')) {
|
||||
errors.push('Client ID is requried');
|
||||
}
|
||||
|
||||
if (!get(this, 'config.clientSecret')) {
|
||||
errors.push('Client Secret is requried');
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
set(this, 'errors', errors.uniq());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,147 +1,264 @@
|
|||
{{#accordion-list showExpandAll=false as | al expandFn |}}
|
||||
<div class="over-hr"><span>{{driverOptionsTitle}}</span></div>
|
||||
<div class="over-hr">
|
||||
<span>
|
||||
{{driverOptionsTitle}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.azure.placement.title')
|
||||
detail=(t 'nodeDriver.azure.placement.detail')
|
||||
title=(t "nodeDriver.azure.access.title")
|
||||
detail=(t "nodeDriver.azure.access.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{form-auth-cloud-credential
|
||||
driverName=driverName
|
||||
errors=errros
|
||||
primaryResource=primaryResource
|
||||
cloudCredentials=cloudCredentials
|
||||
finishAndSelectCloudCredential=(action "finishAndSelectCloudCredential")
|
||||
progressStep=(action "finishAndSelectCloudCredential")
|
||||
cancel=(action "cancel")
|
||||
hideSave=true
|
||||
}}
|
||||
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t "nodeDriver.azure.placement.title")
|
||||
detail=(t "nodeDriver.azure.placement.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.environment.label'}}</label>
|
||||
{{new-select classNames="form-control" content=environments optionLabelPath='value' value=config.environment}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.environment.label"}}
|
||||
</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=environments
|
||||
optionLabelPath="value"
|
||||
value=config.environment
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.region.label'}}</label>
|
||||
{{new-select classNames="form-control" content=regionChoices optionLabelPath='displayName' optionValuePath='name' value=config.location}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.region.label"}}
|
||||
</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=regionChoices
|
||||
optionLabelPath="displayName"
|
||||
optionValuePath="name"
|
||||
value=config.location
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.availabilitySet.label'}}</label>
|
||||
{{input type="text" value=config.availabilitySet classNames="form-control" placeholder=(t 'nodeDriver.azure.availabilitySet.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.availabilitySet.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.availabilitySet
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.availabilitySet.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.resourceGroup.label'}}</label>
|
||||
{{input type="text" value=config.resourceGroup classNames="form-control" placeholder=(t 'nodeDriver.azure.resourceGroup.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.resourceGroup.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.resourceGroup
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.resourceGroup.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.azure.access.title')
|
||||
detail=(t 'nodeDriver.azure.access.detail')
|
||||
title=(t "nodeDriver.azure.network.title")
|
||||
detail=(t "nodeDriver.azure.network.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.subscriptionId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=config.subscriptionId classNames="form-control" placeholder=(t 'nodeDriver.azure.subscriptionId.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.subnet.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.subnet
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.subnet.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.subnetPrefix.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.subnetPrefix
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.subnetPrefix.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.clientId.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=config.clientId classNames="form-control"}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.vnet.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.vnet
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.vnet.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.clientSecret.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=config.clientSecret classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.azure.network.title')
|
||||
detail=(t 'nodeDriver.azure.network.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.subnet.label'}}</label>
|
||||
{{input type="text" value=config.subnet classNames="form-control" placeholder=(t 'nodeDriver.azure.subnet.placeholder')}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.subnetPrefix.label'}}</label>
|
||||
{{input type="text" value=config.subnetPrefix classNames="form-control" placeholder=(t 'nodeDriver.azure.subnetPrefix.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.staticPublicIp.label"}}
|
||||
</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=publicIpChoices
|
||||
optionLabelPath="name"
|
||||
optionValuePath="value"
|
||||
value=publicIpChoice
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.vnet.label'}}</label>
|
||||
{{input type="text" value=config.vnet classNames="form-control" placeholder=(t 'nodeDriver.azure.vnet.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.privateIpAddress.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.privateIpAddress
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.privateIpAddress.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.staticPublicIp.label'}}</label>
|
||||
{{new-select classNames="form-control" content=publicIpChoices optionLabelPath='name' optionValuePath='value' value=publicIpChoice}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.privateIpAddress.label'}}</label>
|
||||
{{input type="text" value=config.privateIpAddress classNames="form-control" placeholder=(t 'nodeDriver.azure.privateIpAddress.placeholder')}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.usePrivateIp.label'}}</label>
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.usePrivateIp.label"}}
|
||||
</label>
|
||||
<div>
|
||||
{{input type="checkbox" checked=config.usePrivateIp disabled=privateSet}}
|
||||
{{input
|
||||
type="checkbox"
|
||||
checked=config.usePrivateIp
|
||||
disabled=privateSet
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.azure.instance.title')
|
||||
detail=(t 'nodeDriver.azure.instance.detail')
|
||||
title=(t "nodeDriver.azure.instance.title")
|
||||
detail=(t "nodeDriver.azure.instance.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.image.label'}}</label>
|
||||
{{input type="text" value=config.image classNames="form-control" placeholder=(t 'nodeDriver.azure.image.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.image.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.image
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.image.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.size.label'}}</label>
|
||||
{{new-select classNames="form-control" content=sizeChoices optionLabelPath='value' optionGroupPath='group' value=config.size}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.size.label"}}
|
||||
</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=sizeChoices
|
||||
optionLabelPath="value"
|
||||
optionGroupPath="group"
|
||||
value=config.size
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.dockerPort.label'}}</label>
|
||||
{{input type="text" value=config.dockerPort classNames="form-control" placeholder=(t 'nodeDriver.azure.dockerPort.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.dockerPort.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.dockerPort
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.dockerPort.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.openPort.label'}}</label>
|
||||
{{input type="text" value=openPorts classNames="form-control" placeholder=(t 'nodeDriver.azure.openPort.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.openPort.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=openPorts
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.openPort.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.sshUser.label'}}</label>
|
||||
{{input type="text" value=config.sshUser classNames="form-control" placeholder=(t 'nodeDriver.azure.sshUser.placeholder')}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.sshUser.label"}}
|
||||
</label>
|
||||
{{input
|
||||
type="text"
|
||||
value=config.sshUser
|
||||
classNames="form-control"
|
||||
placeholder=(t "nodeDriver.azure.sshUser.placeholder")
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.azure.storageType.label'}}</label>
|
||||
{{new-select classNames="form-control" content=storageTypeChoices optionLabelPath='name' optionValuePath='value' value=config.storageType}}
|
||||
<label class="acc-label">
|
||||
{{t "nodeDriver.azure.storageType.label"}}
|
||||
</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=storageTypeChoices
|
||||
optionLabelPath="name"
|
||||
optionValuePath="value"
|
||||
value=config.storageType
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
<div class="over-hr"><span>{{templateOptionsTitle}}</span></div>
|
||||
<div class="over-hr">
|
||||
<span>
|
||||
{{templateOptionsTitle}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{form-name-description
|
||||
model=model
|
||||
|
|
@ -150,7 +267,7 @@
|
|||
|
||||
{{form-user-labels
|
||||
initialLabels=labelResource.labels
|
||||
setLabels=(action 'setLabels')
|
||||
setLabels=(action "setLabels")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
}}
|
||||
|
|
@ -160,6 +277,13 @@
|
|||
showEngineUrl=showEngineUrl
|
||||
}}
|
||||
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel save="save" cancel="cancel" editing=editing}}
|
||||
{{top-errors
|
||||
errors=errors
|
||||
}}
|
||||
|
||||
{{save-cancel
|
||||
save="save"
|
||||
cancel="cancel"
|
||||
editing=editing
|
||||
}}
|
||||
{{/accordion-list}}
|
||||
|
|
|
|||
|
|
@ -31,30 +31,34 @@ const VALID_IMAGES = [
|
|||
];
|
||||
|
||||
export default Component.extend(NodeDriver, {
|
||||
app: service(),
|
||||
app: service(),
|
||||
layout,
|
||||
|
||||
driverName: 'digitalocean',
|
||||
regionChoices: null,
|
||||
model: null,
|
||||
driverName: 'digitalocean',
|
||||
regionChoices: null,
|
||||
model: null,
|
||||
step: 1,
|
||||
sizeChoices: null,
|
||||
imageChoices: null,
|
||||
tags: null,
|
||||
|
||||
step: 1,
|
||||
sizeChoices: null,
|
||||
imageChoices: null,
|
||||
tags: null,
|
||||
config: alias('primaryResource.digitaloceanConfig'),
|
||||
|
||||
config: alias('model.digitaloceanConfig'),
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
const tags = get(this, 'config.tags');
|
||||
|
||||
if (tags) {
|
||||
set(this, 'tags', tags.split(','));
|
||||
}
|
||||
this.initTags();
|
||||
},
|
||||
|
||||
actions: {
|
||||
finishAndSelectCloudCredential(cred) {
|
||||
if (cred) {
|
||||
set(this, 'primaryResource.cloudCredentialId', get(cred, 'id'));
|
||||
|
||||
this.send('getData');
|
||||
}
|
||||
},
|
||||
|
||||
getData(cb) {
|
||||
let promises = {
|
||||
regions: this.apiRequest('regions'),
|
||||
|
|
@ -103,7 +107,9 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
setProperties(this, { errors, });
|
||||
|
||||
cb();
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
@ -134,6 +140,14 @@ export default Component.extend(NodeDriver, {
|
|||
return out;
|
||||
}),
|
||||
|
||||
initTags() {
|
||||
const tags = get(this, 'config.tags');
|
||||
|
||||
if (tags) {
|
||||
set(this, 'tags', tags.split(','));
|
||||
}
|
||||
},
|
||||
|
||||
bootstrap() {
|
||||
let config = get(this, 'globalStore').createRecord({
|
||||
type: 'digitaloceanConfig',
|
||||
|
|
@ -143,15 +157,16 @@ export default Component.extend(NodeDriver, {
|
|||
sshUser: 'root'
|
||||
});
|
||||
|
||||
const model = get(this, 'model');
|
||||
const primaryResource = get(this, 'primaryResource');
|
||||
|
||||
set(model, 'digitaloceanConfig', config);
|
||||
set(primaryResource, 'digitaloceanConfig', config);
|
||||
},
|
||||
|
||||
apiRequest(command, opt, out) {
|
||||
opt = opt || {};
|
||||
|
||||
let url = `${ get(this, 'app.proxyEndpoint') }/`;
|
||||
let url = `${ get(this, 'app.proxyEndpoint') }/`;
|
||||
let cloudCredentialId = get(this, 'primaryResource.cloudCredentialId');
|
||||
|
||||
if ( opt.url ) {
|
||||
url += opt.url.replace(/^http[s]?\/\//, '');
|
||||
|
|
@ -163,8 +178,8 @@ export default Component.extend(NodeDriver, {
|
|||
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-Api-Auth-Header': `Bearer ${ get(this, 'config.accessToken') }`,
|
||||
'Accept': 'application/json',
|
||||
'x-api-cattleauth-header': `Bearer credID=${ cloudCredentialId } passwordField=accessToken`,
|
||||
},
|
||||
}).then((res) => {
|
||||
let body = res.body;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,40 @@
|
|||
<section class="horizontal-form">
|
||||
{{#if (eq step 1)}}
|
||||
<div class="box mt-20">
|
||||
<div class="row">
|
||||
<label class="acc-label">{{t 'nodeDriver.digitalocean.accessToken.label'}}</label>
|
||||
{{input type="password" value=config.accessToken classNames="form-control" placeholder=(t 'nodeDriver.digitalocean.accessToken.placeholder')}}
|
||||
<p class="text-info">{{t 'nodeDriver.digitalocean.accessToken.help' htmlSafe=true}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel
|
||||
save="getData"
|
||||
cancel="cancel"
|
||||
createLabel="nodeDriver.digitalocean.authAccountButton"
|
||||
savingLabel="generic.loading"
|
||||
}}
|
||||
{{else}}
|
||||
{{#accordion-list showExpandAll=false as | al expandFn |}}
|
||||
|
||||
{{#accordion-list showExpandAll=false as | al expandFn |}}
|
||||
|
||||
{{#if (eq step 1)}}
|
||||
{{#accordion-list-item
|
||||
title=(t "nodeDriver.digitalocean.accessToken.label")
|
||||
detail=(t "nodeDriver.digitalocean.accessToken.help" htmlSafe=true)
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{form-auth-cloud-credential
|
||||
driverName=driverName
|
||||
errors=errros
|
||||
primaryResource=primaryResource
|
||||
cloudCredentials=cloudCredentials
|
||||
finishAndSelectCloudCredential=(action "finishAndSelectCloudCredential")
|
||||
progressStep=(action "getData")
|
||||
cancel=(action "cancel")
|
||||
createLabel="nodeDriver.digitalocean.authAccountButton"
|
||||
}}
|
||||
{{/accordion-list-item}}
|
||||
{{top-errors errors=errors}}
|
||||
{{else}}
|
||||
<div class="over-hr mb-20"><span>{{driverOptionsTitle}}</span></div>
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'nodeDriver.digitalocean.droplet.title')
|
||||
detail=(t 'nodeDriver.digitalocean.droplet.detail')
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
title=(t "nodeDriver.digitalocean.droplet.title")
|
||||
detail=(t "nodeDriver.digitalocean.droplet.detail")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.digitalocean.region.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.digitalocean.region.label"}}</label>
|
||||
<select class="form-control" onchange={{action (mut config.region) value="target.value"}}>
|
||||
{{#each regionChoices as |choice|}}
|
||||
<option value={{choice.slug}} selected={{eq config.region choice.slug}}>{{choice.name}}</option>
|
||||
|
|
@ -35,17 +42,17 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.digitalocean.size.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.digitalocean.size.label"}}</label>
|
||||
<select class="form-control" onchange={{action (mut config.size) value="target.value"}}>
|
||||
{{#each filteredSizeChoices as |choice|}}
|
||||
<option value={{choice.slug}} selected={{eq config.size choice.slug}}>{{t 'nodeDriver.digitalocean.sizeLabel' memoryGb=choice.memoryGb highMem=choice.highMem slug=choice.slug disk=choice.disk vcpus=choice.vcpus}}</option>
|
||||
<option value={{choice.slug}} selected={{eq config.size choice.slug}}>{{t "nodeDriver.digitalocean.sizeLabel" memoryGb=choice.memoryGb highMem=choice.highMem slug=choice.slug disk=choice.disk vcpus=choice.vcpus}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.digitalocean.image.label'}}</label>
|
||||
<label class="acc-label">{{t "nodeDriver.digitalocean.image.label"}}</label>
|
||||
<select class="form-control" onchange={{action (mut config.image) value="target.value"}}>
|
||||
{{#each imageChoices as |choice|}}
|
||||
<option value={{choice.slug}} disabled={{choice.disabled}} selected={{eq config.image choice.slug}}>{{choice.distribution}} {{choice.name}}</option>
|
||||
|
|
@ -53,33 +60,33 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.digitalocean.sshUser.label'}}</label>
|
||||
{{input type="text" value=config.sshUser classNames="form-control" placeholder=(t 'nodeDriver.digitalocean.sshUser.placeholder')}}
|
||||
<label class="acc-label">{{t "nodeDriver.digitalocean.sshUser.label"}}</label>
|
||||
{{input type="text" value=config.sshUser classNames="form-control" placeholder=(t "nodeDriver.digitalocean.sshUser.placeholder")}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-3 text-center">
|
||||
<label class="acc-label">
|
||||
{{input type="checkbox" checked=config.backups}}
|
||||
{{t 'nodeDriver.digitalocean.backups.label'}}
|
||||
{{t "nodeDriver.digitalocean.backups.label"}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col span-3 text-center">
|
||||
<label class="acc-label">
|
||||
{{input type="checkbox" checked=config.privateNetworking}}
|
||||
{{t 'nodeDriver.digitalocean.privateNetworking.label'}}
|
||||
{{t "nodeDriver.digitalocean.privateNetworking.label"}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col span-3 text-center">
|
||||
<label class="acc-label">
|
||||
{{input type="checkbox" checked=config.ipv6}}
|
||||
{{t 'nodeDriver.digitalocean.ipv6.label'}}
|
||||
{{t "nodeDriver.digitalocean.ipv6.label"}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col span-3 text-center">
|
||||
<label class="acc-label">
|
||||
{{input type="checkbox" checked=config.monitoring}}
|
||||
{{t 'nodeDriver.digitalocean.monitoring.label'}}
|
||||
{{t "nodeDriver.digitalocean.monitoring.label"}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -87,9 +94,9 @@
|
|||
<div class="col span-6">
|
||||
{{form-value-array
|
||||
initialValues=tags
|
||||
addActionLabel='nodeDriver.digitalocean.tags.addActionLabel'
|
||||
valueLabel='nodeDriver.digitalocean.tags.valueLabel'
|
||||
valuePlaceholder='nodeDriver.digitalocean.tags.placeholder'
|
||||
addActionLabel="nodeDriver.digitalocean.tags.addActionLabel"
|
||||
valueLabel="nodeDriver.digitalocean.tags.valueLabel"
|
||||
valuePlaceholder="nodeDriver.digitalocean.tags.placeholder"
|
||||
changed=(action (mut tags))
|
||||
}}
|
||||
</div>
|
||||
|
|
@ -105,7 +112,7 @@
|
|||
|
||||
{{form-user-labels
|
||||
initialLabels=labelResource.labels
|
||||
setLabels=(action 'setLabels')
|
||||
setLabels=(action "setLabels")
|
||||
expandAll=expandAll
|
||||
expand=(action expandFn)
|
||||
}}
|
||||
|
|
@ -114,9 +121,9 @@
|
|||
machine=model
|
||||
showEngineUrl=showEngineUrl
|
||||
}}
|
||||
{{/accordion-list}}
|
||||
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel save="save" cancel="cancel" editing=editing}}
|
||||
{{/if}}
|
||||
{{top-errors errors=errors}}
|
||||
{{save-cancel save="save" cancel="cancel" editing=editing}}
|
||||
{{/if}}
|
||||
{{/accordion-list}}
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const stringsToParams = (params, str) => {
|
|||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
||||
const paramsToStrings = (strs, param) => {
|
||||
if (param.value && param.key) {
|
||||
|
|
@ -31,27 +31,35 @@ const paramsToStrings = (strs, param) => {
|
|||
}
|
||||
|
||||
return strs;
|
||||
}
|
||||
};
|
||||
|
||||
const initialVAppOptions = {
|
||||
vappIpprotocol: '',
|
||||
vappIpallocationpolicy: '',
|
||||
vappTransport: '',
|
||||
vappProperty: []
|
||||
};
|
||||
|
||||
const getDefaultVappOptions = (networks) => {
|
||||
return {
|
||||
vappIpprotocol: 'IPv4',
|
||||
vappIpallocationpolicy: 'fixedAllocated',
|
||||
vappTransport: 'com.vmware.guestInfo',
|
||||
vappProperty: networksToVappProperties(networks)
|
||||
};
|
||||
};
|
||||
|
||||
const networksToVappProperties = (networks) => {
|
||||
return networks.length === 0
|
||||
? []
|
||||
: networks.reduce(networkToVappProperties, [
|
||||
`guestinfo.dns.servers=\${ dns:${ networks[0] } }`,
|
||||
`guestinfo.dns.domains=\${ searchPath:${ networks[0] } }`
|
||||
]);
|
||||
}
|
||||
|
||||
const getDefaultVappOptions = (networks) => ({
|
||||
vappIpprotocol: 'IPv4',
|
||||
vappIpallocationpolicy: 'fixedAllocated',
|
||||
vappTransport: 'com.vmware.guestInfo',
|
||||
vappProperty: networksToVappProperties(networks)
|
||||
})
|
||||
const networksToVappProperties = (networks) => networks.length === 0
|
||||
? []
|
||||
: networks.reduce(networkToVappProperties, [
|
||||
`guestinfo.dns.servers=\${dns:${ networks[0] }}`,
|
||||
`guestinfo.dns.domains=\${searchPath:${ networks[0] }}`
|
||||
])
|
||||
|
||||
|
||||
const networkToVappProperties = (props, network, i) => {
|
||||
const n = i.toString();
|
||||
|
||||
|
|
@ -62,7 +70,7 @@ const networkToVappProperties = (props, network, i) => {
|
|||
);
|
||||
|
||||
return props;
|
||||
}
|
||||
};
|
||||
|
||||
const getInitialVappMode = (c) => {
|
||||
const vappProperty = c.vappProperty || []
|
||||
|
|
@ -89,7 +97,7 @@ const getInitialVappMode = (c) => {
|
|||
}
|
||||
|
||||
return VAPP_MODE_MANUAL;
|
||||
}
|
||||
};
|
||||
|
||||
export default Component.extend(NodeDriver, {
|
||||
settings: service(),
|
||||
|
|
@ -103,6 +111,7 @@ export default Component.extend(NodeDriver, {
|
|||
vappMode: VAPP_MODE_DISABLED,
|
||||
|
||||
config: alias(`model.${ CONFIG }`),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.initKeyValueParams('config.cfgparam', 'initParamArray');
|
||||
|
|
@ -116,6 +125,9 @@ export default Component.extend(NodeDriver, {
|
|||
},
|
||||
vappPropertyChanged(array) {
|
||||
this.updateKeyValueParams('config.vappProperty', array);
|
||||
},
|
||||
finishAndSelectCloudCredential(credential) {
|
||||
set(this, 'model.cloudCredentialId', get(credential, 'id'))
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -8,29 +8,18 @@
|
|||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.vmwarevsphere.vcenter.label'}}{{field-required}}</label>
|
||||
{{input type="text" class="form-control" value=config.vcenter placeholder=(t 'nodeDriver.vmwarevsphere.vcenter.placeholder')}}
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.vmwarevsphere.vcenterPort.label'}}{{field-required}}</label>
|
||||
{{input-integer min=1 max=65535 class="form-control" value=config.vcenterPort}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.vmwarevsphere.username.label'}}{{field-required}}</label>
|
||||
{{input type="text" value=config.username classNames="form-control"}}
|
||||
</div>
|
||||
{{form-auth-cloud-credential
|
||||
driverName=driverName
|
||||
errors=errros
|
||||
primaryResource=model
|
||||
cloudCredentials=cloudCredentials
|
||||
finishAndSelectCloudCredential=(action "finishAndSelectCloudCredential")
|
||||
progressStep=(action "finishAndSelectCloudCredential")
|
||||
cancel=(action "cancel")
|
||||
hideSave=true
|
||||
}}
|
||||
|
||||
<div class="col span-6">
|
||||
<label class="acc-label">{{t 'nodeDriver.vmwarevsphere.password.label'}}{{field-required}}</label>
|
||||
{{input type="password" value=config.password classNames="form-control"}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">{{t 'nodeDriver.vmwarevsphere.access.help'}}</p>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import { hash } from 'rsvp';
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { get } from '@ember/object';
|
||||
|
||||
export default Route.extend({
|
||||
globalStore: service(),
|
||||
|
||||
model() {
|
||||
return hash({ nodeTemplates: get(this, 'globalStore').findAll('nodeTemplate') });
|
||||
return hash({
|
||||
nodeTemplates: this.globalStore.findAll('nodeTemplate'),
|
||||
cloudCredential: this.globalStore.findAll('cloudcredential'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from './template';
|
||||
import { get, set } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
showAddCloudCredential: null,
|
||||
errors: null,
|
||||
hideSave: false,
|
||||
|
||||
createLabel: 'saveCancel.create',
|
||||
savingLabel: 'generic.loading',
|
||||
|
||||
actions: {
|
||||
doneSavingCloudCredential(cred) {
|
||||
if (cred) {
|
||||
get(this, 'finishAndSelectCloudCredential')(cred)
|
||||
|
||||
set(this, 'showAddCloudCredential', false);
|
||||
}
|
||||
},
|
||||
addCloudCredential() {
|
||||
set(this, 'showAddCloudCredential', true);
|
||||
},
|
||||
cancleNewCloudCredential() {
|
||||
set(this, 'showAddCloudCredential', false);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<label class="acc-label" for="cloud-credential-selection">
|
||||
{{t "formAuthCloudCredential.label"}}
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<select
|
||||
id="cloud-credential-selection"
|
||||
class="form-control inline-block"
|
||||
onchange={{action (mut primaryResource.cloudCredentialId) value="target.value"}}
|
||||
disabled={{if showAddCloudCredential true}}
|
||||
style="max-width: 90%;"
|
||||
>
|
||||
|
||||
{{#unless (not-eq primaryResource.cloudCredentialId primaryResource.cloudCredentialId)}}
|
||||
<option
|
||||
value=
|
||||
selected=true
|
||||
>
|
||||
{{t "formAuthCloudCredential.selectCreds.prompt"}}
|
||||
</option>
|
||||
{{/unless}}
|
||||
|
||||
{{#each cloudCredentials as |choice|}}
|
||||
<option
|
||||
value={{choice.id}}
|
||||
selected={{eq primaryResource.cloudCredentialId choice.id}}
|
||||
>
|
||||
{{choice.displayName}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
|
||||
<button
|
||||
{{action "addCloudCredential"}}
|
||||
class="btn btn-sm bg-primary inline-block"
|
||||
style="margin-top: -5px;"
|
||||
>
|
||||
<i class="icon icon-plus"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
{{#if showAddCloudCredential}}
|
||||
<div class="row">
|
||||
{{cru-cloud-credential
|
||||
driverName=driverName
|
||||
errors=errors
|
||||
disableHeader=true
|
||||
doneSavingCloudCredential=(action "doneSavingCloudCredential")
|
||||
cancelAdd=(action "cancleNewCloudCredential")
|
||||
}}
|
||||
</div>
|
||||
<hr/>
|
||||
{{else}}
|
||||
{{#unless hideSave}}
|
||||
{{save-cancel
|
||||
saveDisabled=(unless primaryResource.cloudCredentialId true)
|
||||
save=progressStep
|
||||
cancel=cancel
|
||||
createLabel=createLabel
|
||||
savingLabel=savingLabel
|
||||
}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
|
@ -4,20 +4,11 @@ import Mixin from '@ember/object/mixin';
|
|||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Mixin.create({
|
||||
classNames: ['modal-container'/* , 'alert' */],
|
||||
classNames: ['modal-container'],
|
||||
|
||||
modalService: service('modal'),
|
||||
modalOpts: alias('modalService.modalOpts'),
|
||||
// Focus does not want to focus on modal el here, dont know why but
|
||||
// esc wont work if a modal doesnt have a focused element
|
||||
// init() {
|
||||
// this._super(...arguments);
|
||||
// Ember.run.scheduleOnce('afterRender', ()=> {
|
||||
// console.log('Focused: ', this.$());
|
||||
// this.$().focus();
|
||||
// });
|
||||
// },
|
||||
//
|
||||
|
||||
keyUp(e) {
|
||||
if (e.which === C.KEY.ESCAPE && this.escToClose()) {
|
||||
this.get('modalService').toggleModal();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import Mixin from '@ember/object/mixin';
|
|||
import NewOrEdit from 'shared/mixins/new-or-edit';
|
||||
import ManageLabels from 'shared/mixins/manage-labels';
|
||||
import { addAction } from 'ui/utils/add-view-action';
|
||||
import { get, set, computed } from '@ember/object';
|
||||
import { get, set, computed, setProperties } from '@ember/object';
|
||||
import { ucFirst } from 'shared/utils/util';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
|
|
@ -66,13 +66,15 @@ export default Mixin.create(NewOrEdit, ManageLabels, {
|
|||
router: service(),
|
||||
globalStore: service(),
|
||||
|
||||
driverName: null,
|
||||
showEngineUrl: true, // On some drivers this isn't configurable
|
||||
driverName: null,
|
||||
showEngineUrl: true, // On some drivers this isn't configurable
|
||||
model: null,
|
||||
labelResource: alias('model'),
|
||||
|
||||
model: null,
|
||||
labelResource: alias('model'),
|
||||
|
||||
actions: {
|
||||
finishAndSelectCloudCredential() {},
|
||||
|
||||
addLabel: addAction('addLabel', '.key'),
|
||||
|
||||
setLabels(labels) {
|
||||
|
|
@ -94,13 +96,7 @@ export default Mixin.create(NewOrEdit, ManageLabels, {
|
|||
this._super(...arguments);
|
||||
|
||||
if ( !get(this, 'editing') && typeof get(this, 'bootstrap') === 'function') {
|
||||
if ( get(this, 'showEngineUrl') ) {
|
||||
set(this, 'model.engineInstallURL', get(this, `settings.${ C.SETTING.ENGINE_URL }`) || '');
|
||||
set(this, 'model.engineRegistryMirror', []);
|
||||
} else {
|
||||
set(this, 'model.engineInstallURL', null);
|
||||
set(this, 'model.engineRegistryMirror', []);
|
||||
}
|
||||
this.initEngineUrl();
|
||||
this.bootstrap();
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +107,37 @@ export default Mixin.create(NewOrEdit, ManageLabels, {
|
|||
// Populate the appropriate *Config field with defaults for your driver
|
||||
},
|
||||
|
||||
cloudCredentials: computed('model.cloudCredentialId', 'driverName', function() {
|
||||
const { driverName } = this;
|
||||
|
||||
return this.globalStore.all('cloudcredential').filter((cc) => {
|
||||
switch (driverName) {
|
||||
case 'digitalocean':
|
||||
if (get(cc, 'isDO')) {
|
||||
return cc;
|
||||
}
|
||||
break;
|
||||
case 'amazonec2':
|
||||
if (get(cc, 'isAmazon')) {
|
||||
return cc;
|
||||
}
|
||||
break;
|
||||
case 'azure':
|
||||
if (get(cc, 'isAzure')) {
|
||||
return cc;
|
||||
}
|
||||
break;
|
||||
case 'vmwarevsphere':
|
||||
if (get(cc, 'isVMware')) {
|
||||
return cc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
});
|
||||
}),
|
||||
|
||||
driverOptionsTitle: computed('driverName', 'intl.locale', function() {
|
||||
const intl = get(this, 'intl');
|
||||
const driver = get(this, 'driverName');
|
||||
|
|
@ -131,6 +158,20 @@ export default Mixin.create(NewOrEdit, ManageLabels, {
|
|||
return intl.t('nodeDriver.templateOptions', { appName });
|
||||
}),
|
||||
|
||||
initEngineUrl() {
|
||||
let engineInstallURL = null;
|
||||
let engineRegistryMirror = [];
|
||||
|
||||
if ( get(this, 'showEngineUrl') ) {
|
||||
engineInstallURL = get(this, `settings.${ C.SETTING.ENGINE_URL }`) || '';
|
||||
}
|
||||
|
||||
setProperties(this, {
|
||||
'model.engineInstallURL': engineInstallURL,
|
||||
'model.engineRegistryMirror': engineRegistryMirror,
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'shared/components/form-auth-cloud-credential/component';
|
||||
|
|
@ -643,6 +643,13 @@ catalogPage:
|
|||
notCompatible: Not Compatible
|
||||
alreadyDeployed: Already Deployed
|
||||
|
||||
cloudKeysPage:
|
||||
addKey: Add Cloud Key
|
||||
index:
|
||||
table:
|
||||
noData: There are no cloud keys yet
|
||||
noMatch: No cloud keys match the current search
|
||||
|
||||
clusterCatalogPage:
|
||||
header: Catalogs
|
||||
|
||||
|
|
@ -4690,6 +4697,13 @@ formAnnotations:
|
|||
errors:
|
||||
invalidJSON: Annotation JSON format is invalid.
|
||||
topLevelValueInvalid: Annotation JSON top-level value must be an object.
|
||||
|
||||
formAuthCloudCredential:
|
||||
label: Cloud Credentials
|
||||
selectCreds:
|
||||
prompt: Select a cloud credential
|
||||
|
||||
|
||||
formJobConfig:
|
||||
title: Job Configuration
|
||||
detail: Configure the desired behavior of jobs.
|
||||
|
|
@ -5182,6 +5196,35 @@ modalAddPayment:
|
|||
euro: "Euro (€)"
|
||||
dollar: "US Dollar ($)"
|
||||
|
||||
modalAddCloudKey:
|
||||
header: Add Cloud Credential
|
||||
type: Cloud Credential Type
|
||||
typeSelect:
|
||||
prompt: Choose a cloud credential provider type
|
||||
amazonec2:
|
||||
accessKey:
|
||||
label: Access Key
|
||||
placeholder: Your AWS access key
|
||||
secretKey:
|
||||
label: Secret Key
|
||||
placeholder: Your AWS secret key
|
||||
azure:
|
||||
clientId:
|
||||
label: Client ID
|
||||
placeholder: Your Client ID
|
||||
clientSecret:
|
||||
label: Client Secret
|
||||
placeholder: Your Client Secret
|
||||
digitalocean:
|
||||
accessToken:
|
||||
label: Access Token
|
||||
placeholder: Your DigitalOcean API access token
|
||||
help: |
|
||||
Paste in a Personal Access Token from the DigitalOcean
|
||||
<a href="https://cloud.digitalocean.com/settings/api/tokens" target="_blank" rel="nofollow noreferrer noopener">Applications & API</a> screen
|
||||
vmwarevsphere:
|
||||
password:
|
||||
label: Password
|
||||
|
||||
modalContainerStop:
|
||||
header: "Are you sure you want to stop"
|
||||
|
|
@ -5190,6 +5233,7 @@ modalContainerStop:
|
|||
label: Timeout
|
||||
button: Stop
|
||||
|
||||
|
||||
modalConfirmDeactivate:
|
||||
header: Are you sure you want to
|
||||
protip: "ProTip: Hold the {key} key while clicking {isServiceButton} to bypass this confirmation."
|
||||
|
|
@ -6735,6 +6779,7 @@ nav:
|
|||
globalDnsProviders: Providers
|
||||
multiClusterApps: Multi-Cluster Apps
|
||||
security:
|
||||
cloudKeys: Cloud Keys
|
||||
tab: Security
|
||||
roles: Roles
|
||||
members: Members
|
||||
|
|
|
|||
Loading…
Reference in New Issue