mirror of https://github.com/rancher/ui.git
469 lines
12 KiB
JavaScript
469 lines
12 KiB
JavaScript
import { alias, equal } from '@ember/object/computed';
|
|
import Driver from 'shared/mixins/node-driver';
|
|
import { get, set } from '@ember/object';
|
|
import { ajaxPromise } from '@rancher/ember-api-store/utils/ajax-promise';
|
|
import Component from '@ember/component';
|
|
import layout from './template';
|
|
import { eachSeries } from 'async';
|
|
|
|
let RANCHER_GROUP = 'rancher-machine';
|
|
let DEFAULT_TEMPLATE = 'Linux Ubuntu 16.04 LTS 64-bit';
|
|
let DEFAULT_ZONE = 'ch-dk-2';
|
|
let RANCHER_INGRESS_RULES = [
|
|
{
|
|
startport: 22,
|
|
endport: 22,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 80,
|
|
endport: 80,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 443,
|
|
endport: 443,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 2376,
|
|
endport: 2376,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 8472,
|
|
endport: 8472,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'UDP'
|
|
},
|
|
{
|
|
startport: 10250,
|
|
endport: 10250,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 30000,
|
|
endport: 32767,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
startport: 30000,
|
|
endport: 32767,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'UDP'
|
|
},
|
|
{
|
|
startport: 6443,
|
|
endport: 6443,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'TCP'
|
|
},
|
|
{
|
|
icmptype: 8,
|
|
icmpcode: 0,
|
|
cidrlist: '0.0.0.0/0',
|
|
protocol: 'ICMP'
|
|
}
|
|
];
|
|
|
|
export default Component.extend(Driver, {
|
|
layout,
|
|
driverName: 'exoscale',
|
|
model: null,
|
|
step: 1,
|
|
|
|
allInstanceProfiles: null,
|
|
allTemplates: null,
|
|
|
|
allZones: null,
|
|
selectedZone: null,
|
|
defaultZone: DEFAULT_ZONE,
|
|
defaultSecurityGroup: RANCHER_GROUP,
|
|
allSecurityGroups: [],
|
|
securityGroup: [],
|
|
whichSecurityGroup: 'default',
|
|
exoscaleApi: 'api.exoscale.ch/compute',
|
|
config: alias('model.exoscaleConfig'),
|
|
isCustomSecurityGroup: equal('whichSecurityGroup', 'custom'),
|
|
|
|
willDestroyElement() {
|
|
set(this, 'errors', null);
|
|
set(this, 'step', 1);
|
|
},
|
|
|
|
actions: {
|
|
/* Login step */
|
|
exoscaleLogin() {
|
|
set(this, 'errors', null);
|
|
set(this, 'step', 2);
|
|
|
|
set(this,
|
|
'config.apiKey',
|
|
(get(this, 'config.apiKey') || '').trim()
|
|
);
|
|
set(this,
|
|
'config.apiSecretKey',
|
|
(get(this, 'config.apiSecretKey') || '').trim()
|
|
);
|
|
|
|
this.apiRequest('listZones').then((res) => {
|
|
let zones = [];
|
|
let defaultZone = null;
|
|
|
|
(res.listzonesresponse.zone || []).forEach((zone) => {
|
|
let obj = {
|
|
id: zone.id,
|
|
name: zone.name,
|
|
isDefault: zone.name === get(this, 'defaultZone')
|
|
};
|
|
|
|
zones.push(obj);
|
|
if (zone.isDefault && !defaultZone) {
|
|
defaultZone = obj;
|
|
}
|
|
});
|
|
|
|
set(this, 'step', 3);
|
|
set(this, 'allZones', zones);
|
|
set(this, 'defaultZone', defaultZone);
|
|
set(this,
|
|
'selectedZone',
|
|
get(this, 'config.zone') ||
|
|
get(this, 'allZones.firstObject.id')
|
|
);
|
|
}, (err) => {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'listzonesresponse',
|
|
'While requesting zones',
|
|
'Authentication failure: please check the provided access credentials'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 1);
|
|
}
|
|
);
|
|
},
|
|
|
|
/* Zone selection */
|
|
selectZone() {
|
|
set(this, 'errors', null);
|
|
|
|
set(this, 'config.zone', get(this, 'selectedZone'));
|
|
(get(this, 'allZones') || []).forEach((zone) => {
|
|
if (zone.id === get(this, 'selectedZone')) {
|
|
set(this, 'config.availabilityZone', zone.name);
|
|
}
|
|
});
|
|
|
|
set(this, 'step', 4);
|
|
this.allSecurityGroups = []
|
|
this.apiRequest('listSecurityGroups').then((res) => {
|
|
// Retrieve the list of security groups.
|
|
(res.listsecuritygroupsresponse.securitygroup || []).forEach((group) => {
|
|
let obj = {
|
|
id: group.id,
|
|
name: group.name,
|
|
description: group.description,
|
|
isDefault: group.name === get(this, 'defaultSecurityGroup')
|
|
};
|
|
|
|
this.allSecurityGroups.push(obj);
|
|
}
|
|
);
|
|
|
|
// Move to next step
|
|
set(this, 'step', 5);
|
|
set(this,
|
|
'securityGroup',
|
|
[get(this, 'config.securityGroup')]);
|
|
}, (err) => {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'listsecuritygroupsresponse',
|
|
'While requesting security groups',
|
|
'Authentication failure: please check the provided access credentials'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 3);
|
|
}
|
|
);
|
|
},
|
|
|
|
/* Security group selection */
|
|
selectSecurityGroup() {
|
|
set(this, 'errors', null);
|
|
|
|
/* When selecting a custom security group, we don't have to do anything more */
|
|
if (get(this, 'isCustomSecurityGroup')) {
|
|
set(this,
|
|
'config.securityGroup',
|
|
[get(this, 'securityGroup')]
|
|
);
|
|
this.fetchInstanceSettings();
|
|
|
|
return;
|
|
}
|
|
|
|
/* Otherwise, do we need to create the default security group? */
|
|
set(this,
|
|
'config.securityGroup',
|
|
[get(this, 'defaultSecurityGroup')]
|
|
);
|
|
let group = get(this, 'defaultSecurityGroup');
|
|
|
|
/* Check if default security group allready exist in all security group*/
|
|
var i;
|
|
|
|
for (i = 0; i < this.allSecurityGroups.length; i++) {
|
|
if (this.allSecurityGroups[i].name === group) {
|
|
set(this, 'config.securityGroup', [group]);
|
|
this.fetchInstanceSettings();
|
|
|
|
/* Already exists, we assume that it contains the appropriate rules */
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* We need to create the security group */
|
|
set(this, 'step', 6);
|
|
this.apiRequest('createSecurityGroup', {
|
|
name: get(this, 'defaultSecurityGroup'),
|
|
description: `${ get(this, 'settings.appName') } default security group`
|
|
}).then((res) => {
|
|
RANCHER_INGRESS_RULES.push({
|
|
startport: 2379,
|
|
endport: 2380,
|
|
'usersecuritygrouplist[0].account': res.createsecuritygroupresponse.securitygroup.account,
|
|
'usersecuritygrouplist[0].group': res.createsecuritygroupresponse.securitygroup.name,
|
|
protocol: 'TCP'
|
|
});
|
|
|
|
return eachSeries(
|
|
RANCHER_INGRESS_RULES,
|
|
(item, cb) => {
|
|
item.securitygroupid =
|
|
res.createsecuritygroupresponse.securitygroup.id;
|
|
this.apiRequest('authorizeSecurityGroupIngress', item).then(() => {
|
|
return cb();
|
|
}, (err) => {
|
|
return cb(err);
|
|
}
|
|
);
|
|
}, (err) => {
|
|
if (err) {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'authorizesecuritygroupingressresponse',
|
|
'While setting default security group',
|
|
'Unable to configure the default security group'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 5);
|
|
} else {
|
|
this.fetchInstanceSettings();
|
|
}
|
|
}
|
|
);
|
|
}, (err) => {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'createsecuritygroupresponse',
|
|
'While creating default security group',
|
|
'Unable to create the default security group'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 5);
|
|
}
|
|
);
|
|
}
|
|
},
|
|
|
|
afterInit: function() {
|
|
this._super();
|
|
|
|
let cur = get(this, 'config.securityGroup');
|
|
|
|
if (cur === RANCHER_GROUP) {
|
|
this.setProperties({
|
|
whichSecurityGroup: 'default',
|
|
securityGroup: null
|
|
});
|
|
} else {
|
|
this.setProperties({
|
|
whichSecurityGroup: 'custom',
|
|
securityGroup: [cur]
|
|
});
|
|
}
|
|
}.on('init'),
|
|
|
|
bootstrap() {
|
|
let config = get(this, 'globalStore').createRecord({
|
|
type: 'exoscaleConfig',
|
|
apiKey: '',
|
|
apiSecretKey: '',
|
|
diskSize: 50,
|
|
image: DEFAULT_TEMPLATE,
|
|
instanceProfile: 'Medium',
|
|
securityGroup: RANCHER_GROUP
|
|
});
|
|
|
|
const model = get(this, 'model');
|
|
|
|
set(model, 'exoscaleConfig', config);
|
|
},
|
|
|
|
fetchInstanceSettings() {
|
|
set(this, 'step', 7);
|
|
|
|
/* First, get a list of templates to get available disk sizes */
|
|
this.apiRequest('listTemplates', {
|
|
templatefilter: 'featured',
|
|
zoneid: get(this, 'config.zone')
|
|
}).then((res) => {
|
|
set(this,
|
|
'allTemplates',
|
|
res.listtemplatesresponse.template
|
|
.filter((item) => item.name.startsWith('Linux'))
|
|
.map((item) => item.name)
|
|
.sort()
|
|
.uniq()
|
|
);
|
|
|
|
/* Also get the instance types */
|
|
return this.apiRequest('listServiceOfferings', { issystem: 'false' }).then((res) => {
|
|
set(this,
|
|
'allInstanceProfiles',
|
|
res.listserviceofferingsresponse.serviceoffering
|
|
.sort((a, b) => {
|
|
if (a.memory < b.memory) {
|
|
return -1;
|
|
}
|
|
if (b.memory < a.memory) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
})
|
|
.map((item) => ({
|
|
name: item.name,
|
|
displaytext: item.displaytext
|
|
}))
|
|
);
|
|
set(this, 'step', 8);
|
|
}, (err) => {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'listserviceofferingsresponse',
|
|
'While getting list of instance types',
|
|
'Unable to get list of instance types'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 5);
|
|
}
|
|
);
|
|
}, (err) => {
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
errors.pushObject(
|
|
this.apiErrorMessage(
|
|
err,
|
|
'listtemplatesresponse',
|
|
'While getting list of available images',
|
|
'Unable to get list of available images'
|
|
)
|
|
);
|
|
set(this, 'errors', errors);
|
|
set(this, 'step', 5);
|
|
}
|
|
);
|
|
},
|
|
|
|
apiErrorMessage(err, kind, prefix, def) {
|
|
let answer = (err.xhr || {}).responseJSON || {};
|
|
let text = (answer[kind] || {}).errortext;
|
|
|
|
if (text) {
|
|
return `${ prefix }: ${ text }`;
|
|
} else {
|
|
return def;
|
|
}
|
|
},
|
|
|
|
apiRequest(command, params) {
|
|
let url = `${ get(this, 'app.proxyEndpoint') }/${ this.exoscaleApi }`;
|
|
|
|
params = params || {};
|
|
params.command = command;
|
|
params.apiKey = get(this, 'config.apiKey');
|
|
params.response = 'json';
|
|
|
|
return ajaxPromise(
|
|
{
|
|
url,
|
|
method: 'POST',
|
|
dataType: 'json',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'X-API-Headers-Restrict': 'Content-Length'
|
|
},
|
|
beforeSend: (xhr, settings) => {
|
|
// Append 'rancher:' to Content-Type
|
|
xhr.setRequestHeader(
|
|
'Content-Type',
|
|
`rancher:${ settings.contentType }`
|
|
);
|
|
|
|
// Compute the signature
|
|
let qs = settings.data
|
|
.split('&')
|
|
.map((q) => q.replace(/\+/g, '%20').replace(/\%5B/g, '[').replace(/\%5D/g, ']'))
|
|
.map(Function.prototype.call, String.prototype.toLowerCase)
|
|
.sort()
|
|
.join('&');
|
|
|
|
settings.data +=
|
|
`&signature=${
|
|
encodeURIComponent(
|
|
AWS.util.crypto.hmac(
|
|
get(this, 'config.apiSecretKey'),
|
|
qs,
|
|
'base64',
|
|
'sha1'
|
|
)
|
|
) }`;
|
|
|
|
return true;
|
|
},
|
|
data: params
|
|
},
|
|
true
|
|
);
|
|
}
|
|
});
|