mirror of https://github.com/rancher/ui.git
545 lines
15 KiB
JavaScript
545 lines
15 KiB
JavaScript
import ClusterDriver from 'shared/mixins/cluster-driver';
|
|
import Component from '@ember/component'
|
|
import layout from './template';
|
|
import {
|
|
INSTANCE_TYPES, nameFromResource, tagsFromResource, EKS_REGIONS, EKS_VERSIONS
|
|
} from 'shared/utils/amazon';
|
|
import {
|
|
get, set, setProperties, computed, observer
|
|
} from '@ember/object';
|
|
import { Promise, resolve } from 'rsvp';
|
|
import { equal } from '@ember/object/computed';
|
|
import { inject as service } from '@ember/service';
|
|
import $ from 'jquery';
|
|
import { isEmpty } from '@ember/utils';
|
|
import { minor, coerce } from 'semver';
|
|
|
|
const RANCHER_GROUP = 'rancher-nodes';
|
|
|
|
export default Component.extend(ClusterDriver, {
|
|
intl: service(),
|
|
versionChoiceService: service('version-choices'),
|
|
layout,
|
|
|
|
configField: 'amazonElasticContainerServiceConfig',
|
|
instanceTypes: INSTANCE_TYPES,
|
|
regionChoices: EKS_REGIONS,
|
|
step: 1,
|
|
serviceRoles: null,
|
|
securityGroups: null,
|
|
whichSecurityGroup: 'default',
|
|
defaultSecurityGroupName: RANCHER_GROUP,
|
|
errors: null,
|
|
serviceRoleMode: 'default',
|
|
vpcSubnetMode: 'default',
|
|
allSecurityGroups: null,
|
|
allKeyPairs: null,
|
|
selectedServiceRole: null,
|
|
selectedGroupedDetails: null,
|
|
kubernetesVersionContent: EKS_VERSIONS,
|
|
|
|
isCustomSecurityGroup: equal('whichSecurityGroup', 'custom'),
|
|
editing: equal('mode', 'edit'),
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
|
|
setProperties(this, {
|
|
clients: {},
|
|
allSubnets: []
|
|
})
|
|
|
|
let config = get(this, 'cluster.amazonElasticContainerServiceConfig');
|
|
|
|
if ( !config ) {
|
|
config = get(this, 'globalStore').createRecord({
|
|
type: 'amazonElasticContainerServiceConfig',
|
|
accessKey: null,
|
|
secretKey: null,
|
|
region: 'us-west-2',
|
|
instanceType: 'm5.large',
|
|
desiredNodes: 1,
|
|
minimumNodes: 1,
|
|
maximumNodes: 1,
|
|
kubernetesVersion: this.kubernetesVersionContent.firstObject,
|
|
});
|
|
|
|
set(this, 'cluster.amazonElasticContainerServiceConfig', config);
|
|
} else {
|
|
if (this.mode === 'edit') {
|
|
setProperties(this, {
|
|
vpcSubnetMode: 'custom',
|
|
serviceRoleMode: 'custom',
|
|
});
|
|
|
|
if (get(this, 'cluster.hasSessionToken')) {
|
|
set(this, 'cluster.amazonElasticContainerServiceConfig.accessKey', null);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
willDestroyElement() {
|
|
setProperties(this, {
|
|
step: 1,
|
|
clients: null,
|
|
allSubnets: null,
|
|
});
|
|
},
|
|
|
|
actions: {
|
|
multiSecurityGroupSelect() {
|
|
let options = Array.prototype.slice.call($('.existing-security-groups')[0], 0);
|
|
let selectedOptions = [];
|
|
|
|
options.filterBy('selected', true).forEach((cap) => {
|
|
return selectedOptions.push(cap.value);
|
|
});
|
|
|
|
set(this, 'config.securityGroups', selectedOptions);
|
|
},
|
|
|
|
multiSubnetGroupSelect() {
|
|
let options = Array.prototype.slice.call($('.existing-subnet-groups')[0], 0);
|
|
let selectedOptions = [];
|
|
|
|
options.filterBy('selected', true).forEach((cap) => {
|
|
return selectedOptions.push(cap.value);
|
|
});
|
|
|
|
set(this, 'config.subnets', selectedOptions);
|
|
},
|
|
|
|
awsLogin(cb) {
|
|
this.listRoles(this.authCreds()).then( (roles) => {
|
|
let eksRoles = [];
|
|
|
|
eksRoles = roles.filter( (role) => {
|
|
//
|
|
let policy = JSON.parse(decodeURIComponent(get(role, 'AssumeRolePolicyDocument')));
|
|
let statement = get(policy, 'Statement');
|
|
let isEksRole = false;
|
|
|
|
statement.forEach( (doc) => {
|
|
let principal = get(doc, 'Principal');
|
|
|
|
if (principal) {
|
|
let service = get(principal, 'Service');
|
|
|
|
if ( service && ( service.includes('eks.amazonaws') || service.includes('EKS') ) && !eksRoles.findBy('RoleId', get(role, 'RoleId'))) {
|
|
// console.log(service.includes('eks'), service.includes('EKS'), eksRoles.findBy('RoleId', get(role, 'RoleId')), role)
|
|
isEksRole = true;
|
|
} else if (get(principal, 'EKS')) {
|
|
// console.log(get(principal, 'EKS'), role);
|
|
isEksRole = true;
|
|
} else {
|
|
isEksRole = false;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (isEksRole) {
|
|
return role;
|
|
}
|
|
});
|
|
|
|
set(this, 'serviceRoles', eksRoles);
|
|
|
|
return this.loadKeyPairs(this.authCreds()).then((/* keyPairs */) => {
|
|
if (this.mode === 'edit') {
|
|
set(this, 'step', 6);
|
|
} else {
|
|
set(this, 'step', 2);
|
|
}
|
|
cb();
|
|
}).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
cb(false, err);
|
|
});
|
|
}).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
cb(false, err);
|
|
});
|
|
},
|
|
|
|
loadVPS(cb) {
|
|
if (get(this, 'selectedServiceRole')) {
|
|
set(this, 'config.serviceRole', get(this, 'selectedServiceRole'));
|
|
}
|
|
|
|
this.loadVpcs(this.authCreds()).then(() => {
|
|
set(this, 'step', 3);
|
|
|
|
cb();
|
|
}).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
cb(false, err);
|
|
});
|
|
},
|
|
|
|
setVPCS(cb) {
|
|
if (get(this, 'vpcSubnetMode') === 'custom') {
|
|
this.loadSubnets(this.authCreds()).then(() => {
|
|
set(this, 'step', 4);
|
|
|
|
cb();
|
|
}).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
cb(false, err);
|
|
});
|
|
} else {
|
|
set(this, 'step', 6);
|
|
}
|
|
},
|
|
|
|
setSubnets(cb) {
|
|
this.loadSecurityGroups(this.authCreds()).then(() => {
|
|
set(this, 'step', 5);
|
|
|
|
cb();
|
|
}).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
cb(false, err);
|
|
});
|
|
},
|
|
},
|
|
|
|
publicIpChanged: observer('step', 'config.associateWorkerNodePublicIp', function() {
|
|
if (!get(this, 'config.associateWorkerNodePublicIp')) {
|
|
set(this, 'vpcSubnetMode', 'custom');
|
|
}
|
|
}),
|
|
|
|
desiredNodesChanged: observer('config.desiredNodes', function() {
|
|
const desiredNodes = get(this, 'config.desiredNodes');
|
|
const config = get(this, 'config');
|
|
|
|
setProperties(config, {
|
|
minimumNodes: desiredNodes,
|
|
maximumNodes: desiredNodes
|
|
})
|
|
}),
|
|
|
|
vpcSubnetModeDidChange: observer('step', 'vpcSubnetMode', function() {
|
|
const {
|
|
vpcSubnetMode: mode,
|
|
editing,
|
|
step,
|
|
} = this;
|
|
|
|
if ( !editing && mode === 'custom' ) {
|
|
const vpc = get(this, 'filteredVpcs.firstObject.id');
|
|
|
|
if (step <= 3) {
|
|
if ( vpc ) {
|
|
set(this, 'config.virtualNetwork', vpc);
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
|
|
serviceRoleModeDidChange: observer('serviceRoleMode', function() {
|
|
const mode = get(this, 'serviceRoleMode');
|
|
|
|
if ( mode === 'custom' ) {
|
|
const role = get(this, 'serviceRoles.firstObject.RoleName');
|
|
|
|
if ( role ) {
|
|
set(this, 'selectedServiceRole', role);
|
|
}
|
|
} else {
|
|
set(this, 'selectedServiceRole', null);
|
|
}
|
|
}),
|
|
|
|
vpcsChanged: observer('config.virtualNetwork', 'vpcSubnetMode', function() {
|
|
if (!this.primaryResource.isTransitioning) {
|
|
const vnet = get(this, 'config.virtualNetwork');
|
|
const subnets = get(this, 'config.subnets');
|
|
const mode = get(this, 'vpcSubnetMode');
|
|
const hasInitializedValues = vnet || subnets;
|
|
|
|
if (vnet && mode === 'custom') {
|
|
this.loadSubnets(this.authCreds()).catch((err) => {
|
|
get(this, 'errors').pushObject(err);
|
|
});
|
|
// We check for initialized values here because as part of
|
|
// the saving process this observer gets triggered with
|
|
// uninitialized values. This was causing a save to switch
|
|
// the step to step 3 rather than remaining on the last
|
|
// page until the saving was complete.
|
|
} else if (mode === 'default' && hasInitializedValues) {
|
|
setProperties(get(this, 'config'), {
|
|
virtualNetwork: null,
|
|
subnets: [],
|
|
});
|
|
|
|
set(this, 'step', 3);
|
|
}
|
|
}
|
|
}),
|
|
|
|
versionChoices: computed('editing', 'versions', function() {
|
|
const {
|
|
config : { kubernetesVersion: initialVersion },
|
|
intl,
|
|
kubernetesVersionContent,
|
|
mode,
|
|
} = this;
|
|
const versionChoices = this.versionChoiceService.parseCloudProviderVersionChoices(kubernetesVersionContent.slice(), initialVersion, mode);
|
|
|
|
// only EKS and edit - user can only upgrade a single minor version at a time
|
|
if (this.editing) {
|
|
const initalMinorVersion = parseInt(minor(coerce(initialVersion)), 10);
|
|
|
|
versionChoices.forEach((vc) => {
|
|
const vcMinorV = parseInt(minor(coerce(vc.value)), 10);
|
|
const diff = vcMinorV - initalMinorVersion;
|
|
|
|
if (diff > 1) {
|
|
setProperties(vc, {
|
|
disabled: true,
|
|
label: `${ vc.label } ${ intl.t('formVersions.eks.label') }`,
|
|
});
|
|
}
|
|
})
|
|
}
|
|
|
|
return versionChoices;
|
|
}),
|
|
|
|
|
|
filteredKeyPairs: computed('allKeyPairs', function() {
|
|
return get(this, 'allKeyPairs').sortBy('KeyName');
|
|
}),
|
|
|
|
filteredSubnets: computed('allSubnets', 'config.virtualNetwork', function() {
|
|
return get(this, 'allSubnets').filterBy('VpcId', get(this, 'config.virtualNetwork')).map( (subnet) => {
|
|
return {
|
|
subnetName: nameFromResource(subnet, 'SubnetId'),
|
|
subnetId: subnet.SubnetId,
|
|
}
|
|
}).sortBy('subnetName');
|
|
}),
|
|
|
|
|
|
filteredVpcs: computed('allVpcs', function() {
|
|
return (get(this, 'allVpcs') || []).filterBy('State', 'available').map((vpc) => {
|
|
return {
|
|
id: get(vpc, 'VpcId'),
|
|
label: `${ get(vpc, 'VpcId') } (${ get(vpc, 'CidrBlock') })`
|
|
};
|
|
}).sortBy('label');
|
|
}),
|
|
|
|
filteredSecurityGroups: computed('allSecurityGroups', 'config.virtualNetwork', function() {
|
|
return get(this, 'allSecurityGroups').filterBy('VpcId', get(this, 'config.virtualNetwork')).sortBy('GroupName');
|
|
}),
|
|
|
|
readableServiceRole: computed('config.serviceRole', 'serviceRoles', function() {
|
|
const roles = get(this, 'serviceRoles');
|
|
const selectedRole = get(this, 'config.serviceRole');
|
|
const match = roles.findBy('RoleName', selectedRole);
|
|
|
|
return match && match.RoleName ? get(match, 'RoleName') : this.intl.t('nodeDriver.amazoneks.role.noneSelected');
|
|
}),
|
|
|
|
canSaveVPC: computed('vpcSubnetMode', 'selectedGroupedDetails', 'config.virtualNetwork', 'config.subnets.[]', function() {
|
|
const mode = get(this, 'vpcSubnetMode');
|
|
const config = get(this, 'config');
|
|
let disabled = true;
|
|
|
|
if (mode === 'default' || get(config, 'virtualNetwork') ) {
|
|
disabled = false;
|
|
}
|
|
|
|
return disabled;
|
|
}),
|
|
|
|
canSaveSG: computed('config.securityGroups.[]', function() {
|
|
const sg = get(this, 'config.securityGroups');
|
|
|
|
let disabled = true;
|
|
|
|
if (sg && sg.length > 0) {
|
|
disabled = false;
|
|
}
|
|
|
|
return disabled;
|
|
}),
|
|
|
|
authCreds() {
|
|
const config = get(this, 'config');
|
|
|
|
let {
|
|
accessKey, secretKey, region, sessionToken
|
|
} = config;
|
|
|
|
accessKey = (accessKey || '').trim();
|
|
secretKey = ( secretKey || '' ).trim();
|
|
|
|
setProperties(this, {
|
|
'errors': [],
|
|
'config.accessKey': accessKey,
|
|
'config.secretKey': secretKey,
|
|
});
|
|
|
|
const auth = {
|
|
region,
|
|
accessKeyId: accessKey,
|
|
secretAccessKey: secretKey,
|
|
};
|
|
|
|
if (sessionToken) {
|
|
let token = sessionToken.trim();
|
|
|
|
set(auth, 'sessionToken', token);
|
|
set(this, 'config.sessionToken', token);
|
|
}
|
|
|
|
return auth;
|
|
},
|
|
|
|
loadVpcs(auth) {
|
|
return this.listVPCs(auth).then( (resp) => {
|
|
let { vpcs } = resp;
|
|
|
|
let def = vpcs.findBy('IsDefault');
|
|
|
|
if (def && def.VpcId) {
|
|
set(this, 'config.virtualNetwork', get(def, 'VpcId'));
|
|
}
|
|
|
|
return resolve(set(this, 'allVpcs', vpcs));
|
|
});
|
|
},
|
|
|
|
loadSubnets(auth) {
|
|
return this.listSubnets(auth).then( (resp) => {
|
|
return resolve(set(this, 'allSubnets', resp));
|
|
});
|
|
},
|
|
|
|
loadSecurityGroups(auth) {
|
|
return this.listSecurityGroups(auth).then( (resp) => {
|
|
return resolve(set(this, 'allSecurityGroups', resp));
|
|
});
|
|
},
|
|
|
|
loadKeyPairs(auth) {
|
|
return this.listKeyPairs(auth).then( (resp) => {
|
|
return resolve(set(this, 'allKeyPairs', resp));
|
|
});
|
|
},
|
|
|
|
listKeyPairs(auth) {
|
|
return new Promise((resolve, reject) => {
|
|
const ec2 = new AWS.EC2(auth);
|
|
|
|
ec2.describeKeyPairs({}, (err, data) => {
|
|
if (err) {
|
|
console.log(err, err.stack);
|
|
reject(err);
|
|
}
|
|
|
|
resolve(data.KeyPairs);
|
|
});
|
|
})
|
|
},
|
|
|
|
listRoles(auth) {
|
|
// TODO There is no IAM endpoint in cn-northwest-1 region. We need to use cn-north-1 for now. So users chould be able to create EKS cluster in cn-northwest-1.
|
|
|
|
const { region } = auth || {};
|
|
|
|
if ( region === 'cn-northwest-1' ) {
|
|
auth.region = 'cn-north-1';
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const IAM = new AWS.IAM(auth);
|
|
|
|
IAM.listRoles({}, (err, data) => {
|
|
if (err) {
|
|
console.log(err, err.stack);
|
|
reject(err);
|
|
}
|
|
|
|
resolve(data.Roles);
|
|
});
|
|
});
|
|
},
|
|
|
|
listVPCs(auth) {
|
|
return new Promise((resolve, reject) => {
|
|
const ec2 = new AWS.EC2(auth);
|
|
const vpcNames = {};
|
|
const vpcTags = {};
|
|
|
|
ec2.describeVpcs({}, (err, vpcs) => {
|
|
if ( err ) {
|
|
return reject(err);
|
|
}
|
|
|
|
vpcs.Vpcs.forEach((vpc) => {
|
|
vpcNames[vpc.VpcId] = nameFromResource(vpc, 'VpcId');
|
|
vpcTags[vpc.VpcId] = tagsFromResource(vpc);
|
|
});
|
|
|
|
return resolve({
|
|
vpcNames,
|
|
vpcTags,
|
|
vpcs: vpcs.Vpcs
|
|
});
|
|
});
|
|
});
|
|
},
|
|
|
|
listSubnets(auth) {
|
|
const ec2 = new AWS.EC2(auth);
|
|
const rName = get(this, 'config.region');
|
|
let subnets = [];
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
ec2.describeSubnets({}, (err, data) => {
|
|
if ( err ) {
|
|
reject(err)
|
|
}
|
|
|
|
set(this, `clients.${ rName }`, ec2)
|
|
|
|
subnets = data.Subnets;
|
|
|
|
resolve(subnets);
|
|
});
|
|
});
|
|
},
|
|
|
|
listSecurityGroups(auth) {
|
|
const ec2 = new AWS.EC2(auth);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
ec2.describeSecurityGroups({}, (err, data) => {
|
|
if ( err ) {
|
|
reject(err)
|
|
}
|
|
|
|
resolve(data.SecurityGroups);
|
|
});
|
|
});
|
|
},
|
|
|
|
willSave() {
|
|
// temporary measure put in place for rancher/rancher#24652
|
|
const { config: { subnets } } = this;
|
|
|
|
if (isEmpty(subnets)) {
|
|
set(this, 'config.subnets', []);
|
|
}
|
|
|
|
return this._super(...arguments);
|
|
},
|
|
|
|
});
|