ui/lib/shared/addon/components/cluster-driver/driver-tencenttke/component.js

583 lines
16 KiB
JavaScript

import Component from '@ember/component'
import ClusterDriver from 'shared/mixins/cluster-driver';
import layout from './template';
import { inject as service } from '@ember/service';
import {
get, set, computed, observer, setProperties
} from '@ember/object';
import { resolve, reject, all } from 'rsvp';
import { equal } from '@ember/object/computed'
const ENDPOINT = 'tencentcloudapi.com/';
const CCS_ENDPOINT = 'api.qcloud.com/v2/index.php';
const DATA_DISK = 'DATA_DISK'
const SYSTEM_DISK = 'SYSTEM_DISK'
const OS = [
{
label: 'Ubuntu Server 16.04.1 LTS 64bit',
value: 'ubuntu16.04.1 LTSx86_64'
},
{
label: 'CentOS 7.2 64bit',
value: 'centos7.2x86_64'
}
]
const REGIONS = [
{
label: 'ap-guangzhou',
value: 'ap-guangzhou'
}, {
label: 'ap-shanghai',
value: 'ap-shanghai'
}, {
label: 'ap-beijing',
value: 'ap-beijing'
}, {
label: 'ap-hongkong',
value: 'ap-hongkong'
}, {
label: 'ap-singapore',
value: 'ap-singapore'
}, {
label: 'ap-chengdu',
value: 'ap-chengdu'
}, {
label: 'ap-mumbai',
value: 'ap-mumbai'
}, {
label: 'ap-tokyo',
value: 'ap-tokyo'
}, {
label: 'ap-bangkok',
value: 'ap-bangkok'
}, {
label: 'na-siliconvalley',
value: 'na-siliconvalley'
}, {
label: 'na-ashburn',
value: 'na-ashburn'
}, {
label: 'eu-moscow',
value: 'eu-moscow'
}, {
label: 'eu-frankfurt',
value: 'eu-frankfurt'
}];
const VERSIONS = [
{
label: '1.10.5',
value: '1.10.5'
},
{
label: '1.12.4',
value: '1.12.4'
},
{
label: '1.14.3',
value: '1.14.3'
},
{
label: '1.16.3',
value: '1.16.3'
},
];
const BAND_WIDTH = [
{
label: 'clusterNew.tencenttke.bandwidthType.hour',
value: 'PayByHour'
},
{
label: 'clusterNew.tencenttke.bandwidthType.traffic',
value: 'PayByTraffic'
}
];
export default Component.extend(ClusterDriver, {
intl: service(),
layout,
configField: 'tencentEngineConfig',
step: 1,
regionChoices: REGIONS,
versionChoices: VERSIONS,
osChoices: OS,
bandWidthChoices: BAND_WIDTH,
zoneChoices: null,
vpcChoices: null,
sgChoices: null,
keyChoices: null,
allSubnets: null,
allInstances: null,
isNew: equal('mode', 'new'),
editing: equal('mode', 'edit'),
init() {
this._super(...arguments);
let config = get(this, 'cluster.tencentEngineConfig');
if ( !config ) {
config = this.get('globalStore').createRecord({
type: 'tencentEngineConfig',
clusterCidr: '172.16.0.0/16',
clusterVersion: get(VERSIONS, 'lastObject.value'),
region: 'ap-guangzhou',
secretId: null,
secretKey: null,
zoneId: null,
vpcId: null,
subnetId: null,
instanceType: 'S2.MEDIUM4',
osName: 'ubuntu16.04.1 LTSx86_64',
sgId: null,
rootSize: 100,
storageSize: 100,
cvmType: 'PayByHour',
wanIp: 1,
isVpcGateway: 0,
emptyCluster: false,
bandwidthType: 'PayByHour',
bandwidth: 10,
keyId: null,
nodeCount: 1,
});
set(this, 'cluster.tencentEngineConfig', config);
}
},
actions: {
tencentLogin(cb) {
setProperties(this, {
'errors': null,
'config.secretId': (get(this, 'config.secretId') || '').trim(),
'config.secretKey': (get(this, 'config.secretKey') || '').trim(),
});
const errors = get(this, 'errors') || [];
const intl = get(this, 'intl');
const secretId = get(this, 'config.secretId');
const secretKey = get(this, 'config.secretKey');
if ( !secretId ) {
errors.push(intl.t('clusterNew.tencenttke.secretId.required'));
}
if ( !secretKey ) {
errors.push(intl.t('clusterNew.tencenttke.secretKey.required'));
}
if (errors.length > 0) {
set(this, 'errors', errors);
cb();
return;
}
return all([
this.fetchVpcs(),
this.fetchSubnets()
]).then(() => {
set(this, 'step', 2);
cb(true);
}).catch(() => {
cb(false);
});
},
loadNodeConfig(cb) {
setProperties(this, { 'errors': null });
const errors = get(this, 'errors') || [];
const intl = get(this, 'intl');
const {
clusterCidr, vpcId, nodeCount
} = get(this, 'config');
if ( !clusterCidr ) {
errors.push(intl.t('clusterNew.tencenttke.cidr.required'));
}
if ( !vpcId ) {
errors.push(intl.t('clusterNew.tencenttke.vpc.required'));
}
if ( !nodeCount ) {
errors.push(intl.t('clusterNew.tencenttke.nodeCount.required'));
}
if (errors.length > 0) {
set(this, 'errors', errors);
cb();
return;
}
return this.checkCidr().then((res) => {
if (get(res, 'code') === 0 ) {
all([
this.fetchZones(),
this.fetchNodeTypes(),
]).then(() => {
set(this, 'step', 3);
cb(true);
}).catch(() => {
cb(false);
});
} else {
const error = decodeURIComponent(get(res, 'message'));
if ( error ) {
set(this, 'errors', [error]);
}
cb(false);
}
}).catch((error) => {
set(this, 'errors', [error]);
cb(false);
});
},
loadInstanceConfig(cb) {
setProperties(this, { 'errors': null });
const errors = get(this, 'errors') || [];
const intl = get(this, 'intl');
const { zoneId, subnetId } = get(this, 'config');
if ( !zoneId ) {
errors.push(intl.t('clusterNew.tencenttke.zone.required'));
}
if ( !subnetId ) {
errors.push(intl.t('clusterNew.tencenttke.subnet.required'));
}
if (errors.length > 0) {
set(this, 'errors', errors);
cb();
return;
}
return all([
this.fetchSecurityGroups(),
this.fetchKeyPairs(),
this.fetchDiskConfigQuota(),
]).then(() => {
set(this, 'step', 4);
cb(true);
}).catch(() => {
cb(false);
});
},
save(cb) {
setProperties(this, { 'errors': null });
const errors = get(this, 'errors') || [];
const intl = get(this, 'intl');
const { sgId, keyId } = get(this, 'config') ;
if ( !sgId ) {
errors.push(intl.t('clusterNew.tencenttke.securityGroup.required'));
}
if ( !keyId ) {
errors.push(intl.t('clusterNew.tencenttke.keyPair.required'));
}
if (errors.length > 0) {
set(this, 'errors', errors);
cb();
return;
}
this.send('driverSave', cb);
}
},
clusterNameDidChange: observer('cluster.name', function() {
set(this, 'config.clusterName', get(this, 'cluster.name'));
}),
subnetIdObserver: observer('selectedZone', 'allSubnets', 'config.vpcId', 'vpcChoices.[]', function() {
if ( !get(this, 'selectedZone') || !get(this, 'allSubnets') ) {
return;
}
const subnets = get(this, 'allSubnets').filter((subnet) => get(subnet, 'vpcId') === get(this, 'config.vpcId') && get(subnet, 'zone') === get(this, 'selectedZone.label'));
const subnetId = get(this, 'config.subnetId');
if ( get(this, 'isNew') && get(subnets, 'length') ) {
set(this, 'config.subnetId', get(subnets, 'firstObject.value'));
} else {
const found = subnets.findBy('value', subnetId);
if ( !found ) {
set(this, 'config.subnetId', null);
}
}
}),
subnetChoices: computed('allSubnets', 'config.vpcId', 'selectedZone.label', 'vpcChoices.[]', function() {
if ( !get(this, 'selectedZone') || !get(this, 'allSubnets') ) {
return;
}
const subnets = get(this, 'allSubnets').filter((subnet) => get(subnet, 'vpcId') === get(this, 'config.vpcId') && get(subnet, 'zone') === get(this, 'selectedZone.label'));
return subnets;
}),
instanceChoices: computed('allInstances', 'config.instanceType', 'selectedZone.label', function() {
if ( !get(this, 'selectedZone') || !get(this, 'allInstances') ) {
return;
}
const instances = get(this, 'allInstances').filterBy('zone', get(this, 'selectedZone.label'));
const instanceType = get(this, 'config.instanceType');
const found = instances.findBy('value', instanceType);
if ( !found ) {
set(this, 'config.instanceType', null);
}
return instances;
}),
selectedZone: computed('config.zoneId', 'zoneChoices', function() {
const zoneChoices = get(this, 'zoneChoices') || [];
return zoneChoices.findBy('value', get(this, 'config.zoneId'));
}),
storageDiskChoices: computed('diskConfigSet.[]', function() {
return this.getDiskChoices(DATA_DISK)
}),
rootDiskChoices: computed('diskConfigSet.[]', function() {
return this.getDiskChoices(SYSTEM_DISK)
}),
maxDataDiskSize: computed('config.storageType', function() {
const { storageDiskChoices = [] } = this
const disk = storageDiskChoices.findBy('value', get(this, 'config.storageType'))
return get(disk, 'maxDiskSize')
}),
minDataDiskSize: computed('config.storageType', function() {
const { storageDiskChoices = [] } = this
const disk = storageDiskChoices.findBy('value', get(this, 'config.storageType'))
return get(disk, 'minDiskSize')
}),
maxSystemDiskSize: computed('config.rootType', function() {
const { rootDiskChoices = [] } = this
const disk = rootDiskChoices.findBy('value', get(this, 'config.rootType'))
return get(disk, 'maxDiskSize')
}),
minSystemDiskSize: computed('config.rootType', function() {
const { rootDiskChoices = [] } = this
const disk = rootDiskChoices.findBy('value', get(this, 'config.rootType'))
return get(disk, 'minDiskSize')
}),
checkCidr() {
if ( get(this, 'isNew') ) {
return this.queryFromTencent('ccs', 'CheckClusterCIDR', CCS_ENDPOINT, {
clusterCIDR: get(this, 'config.clusterCidr'),
vpcId: get(this, 'config.vpcId'),
});
} else {
return resolve({ code: 0 });
}
},
queryFromTencent(product, action, endpoint = ENDPOINT, extraParams = {}) {
const data = {
Action: action,
Nonce: Math.round(Math.random() * 65535),
Region: get(this, 'config.region'),
SecretId: get(this, 'config.secretId'),
SignatureMethod: 'HmacSHA1',
Timestamp: Math.round(Date.now() / 1000),
Version: '2017-03-12',
...extraParams,
}
let url = `${ product }.${ endpoint }?`;
const params = [];
Object.keys(data).sort().forEach((key) => {
params.push(`${ key }=${ data[key] }`);
});
url += params.join('&');
url += `&Signature=${ encodeURIComponent(AWS.util.crypto.hmac(
get(this, 'config.secretKey'),
`GET${ url }`,
'base64',
'sha1'
)) }`
return get(this, 'globalStore').rawRequest({
url: `/meta/proxy/https:/${ url }`,
method: 'GET'
}).then((xhr) => {
const error = get(xhr, 'body.Response.Error.Message');
if ( error ) {
set(this, 'errors', [error]);
return reject();
}
return get(xhr, 'body.Response') || JSON.parse(get(xhr, 'body'));
}).catch((xhr) => {
const error = get(xhr, 'body.Response.Error.Message') || JSON.stringify(xhr);
set(this, 'errors', [error]);
return reject();
});
},
fetchVpcs() {
return this.queryFromTencent('vpc', 'DescribeVpcs').then((res) => {
set(this, 'vpcChoices', get(res, 'VpcSet').map((vpc) => {
return {
label: get(vpc, 'VpcName'),
value: get(vpc, 'VpcId')
};
}));
if ( !get(this, 'config.vpcId') && get(this, 'vpcChoices.length') ) {
set(this, 'config.vpcId', get(this, 'vpcChoices.firstObject.value'));
}
})
},
fetchSubnets() {
return this.queryFromTencent('vpc', 'DescribeSubnets').then((res) => {
set(this, 'allSubnets', get(res, 'SubnetSet').map((subnet) => {
return {
label: get(subnet, 'SubnetName'),
value: get(subnet, 'SubnetId'),
vpcId: get(subnet, 'VpcId'),
zone: get(subnet, 'Zone'),
};
}));
})
},
fetchNodeTypes() {
return this.queryFromTencent('cvm', 'DescribeInstanceTypeConfigs').then((res) => {
set(this, 'allInstances', get(res, 'InstanceTypeConfigSet').map((instance) => {
return {
value: get(instance, 'InstanceType'),
label: `${ get(instance, 'InstanceType') } (CPU ${ get(instance, 'CPU') } Memory ${ get(instance, 'Memory') } GiB)`,
group: get(instance, 'InstanceFamily'),
zone: get(instance, 'Zone'),
};
}));
});
},
fetchSecurityGroups() {
return this.queryFromTencent('vpc', 'DescribeSecurityGroups').then((res) => {
set(this, 'sgChoices', get(res, 'SecurityGroupSet').map((zone) => {
return {
label: get(zone, 'SecurityGroupName'),
value: get(zone, 'SecurityGroupId')
};
}));
if ( !get(this, 'config.sgId') && get(this, 'sgChoices.length') ) {
set(this, 'config.sgId', get(this, 'sgChoices.firstObject.value'));
}
});
},
fetchDiskConfigQuota() {
return this.queryFromTencent('cbs', 'DescribeDiskConfigQuota', ENDPOINT, {
InquiryType: 'INQUIRY_CVM_CONFIG',
'Zones.0': ((get(this, 'zoneChoices') || []).findBy('value', get(this, 'config.zoneId')) || {}).label,
'InstanceFamilies.0': (get(this, 'config.instanceType') || '').split('.').get('firstObject')
}).then((res) => {
const diskConfigSet = get(res, 'DiskConfigSet').filter((d) => d.DiskChargeType === 'POSTPAID_BY_HOUR')
const dataDisks = diskConfigSet.filter((d) => d.DiskUsage === DATA_DISK)
const systemDisks = diskConfigSet.filter((d) => d.DiskUsage === SYSTEM_DISK)
if (get(this, 'isNew')) {
setProperties(this, {
'config.storageType': get(dataDisks, 'firstObject.DiskType'),
'config.rootType': get(systemDisks, 'firstObject.DiskType'),
})
}
set(this, 'diskConfigSet', diskConfigSet)
});
},
fetchKeyPairs() {
return this.queryFromTencent('cvm', 'DescribeKeyPairs').then((res) => {
set(this, 'keyChoices', get(res, 'KeyPairSet').map((key) => {
return {
label: get(key, 'KeyName'),
value: get(key, 'KeyId')
};
}));
if ( !get(this, 'config.keyId') && get(this, 'keyChoices.length') ) {
set(this, 'config.keyId', get(this, 'keyChoices.firstObject.value'));
}
});
},
fetchZones() {
return this.queryFromTencent('cvm', 'DescribeZones').then((res) => {
set(this, 'zoneChoices', get(res, 'ZoneSet').filterBy('ZoneState', 'AVAILABLE').map((zone) => {
return {
label: get(zone, 'Zone'),
value: get(zone, 'ZoneId')
};
}));
if ( !get(this, 'config.zoneId') && get(this, 'zoneChoices.length') ) {
set(this, 'config.zoneId', get(this, 'zoneChoices.firstObject.value'));
}
});
},
getDiskChoices(usage) {
const { diskConfigSet = [] } = this
return diskConfigSet.filter((d) => d.DiskUsage === usage).map((d) => {
return {
label: `clusterNew.tencenttke.disk.${ d.DiskType }`,
value: d.DiskType,
maxDiskSize: d.MaxDiskSize,
minDiskSize: d.MinDiskSize,
}
})
},
});