ui/lib/nodes/addon/components/driver-digitalocean/component.js

191 lines
5.0 KiB
JavaScript

import { hash } from 'rsvp';
import {
get, set, computed, observer, setProperties
} from '@ember/object';
import { alias } from '@ember/object/computed';
import Component from '@ember/component';
import NodeDriver, { registerDisplayLocation, registerDisplaySize } from 'shared/mixins/node-driver';
import fetch from '@rancher/ember-api-store/utils/fetch';
import { addQueryParam, addQueryParams } from 'shared/utils/util';
import layout from './template';
import { inject as service } from '@ember/service';
registerDisplayLocation(DRIVER, 'config.region');
registerDisplaySize(DRIVER, 'config.size');
const DRIVER = 'digitalocean';
const DIGITALOCEAN_API = 'api.digitalocean.com/v2';
const VALID_IMAGES = [
'rancheros',
'centos-7-x64',
'coreos-alpha',
'coreos-beta',
'coreos-stable',
'debian-8-x64',
'debian-9-x64',
'fedora-27-x64',
'fedora-28-x64',
'ubuntu-14-04-x64',
'ubuntu-16-04-x64',
'ubuntu-18-04-x64',
];
export default Component.extend(NodeDriver, {
app: service(),
layout,
driverName: 'digitalocean',
regionChoices: null,
model: null,
step: 1,
sizeChoices: null,
imageChoices: null,
tags: null,
config: alias('model.digitaloceanConfig'),
init() {
this._super(...arguments);
const tags = get(this, 'config.tags');
if (tags) {
set(this, 'tags', tags.split(','));
}
},
actions: {
getData(cb) {
let promises = {
regions: this.apiRequest('regions'),
images: this.apiRequest('images', { params: { type: 'distribution' } }),
sizes: this.apiRequest('sizes')
};
hash(promises).then((hash) => {
let filteredRegions = hash.regions.regions.filter((region) => {
return region.available && (region.features.indexOf('metadata') >= 0);
}).sortBy('name');
let filteredSizes = hash.sizes.sizes.map((size) => {
size.memoryGb = size.memory / 1024;
size.highMem = size.slug.indexOf('m-') >= 0;
return size;
}).filter((size) => {
return size.available;
}).sortBy('highMem', 'memory');
let filteredImages = hash.images.images.filter((image) => {
// 64-bit only
return !((image.name || '').match(/x32$/));
}).map((image) => {
image.disabled = VALID_IMAGES.indexOf(image.slug) === -1;
return image;
});
filteredImages = filteredImages.sortBy('distribution', 'name');
setProperties(this, {
regionChoices: filteredRegions,
sizeChoices: filteredSizes,
imageChoices: filteredImages,
step: 2,
errors: null,
});
this.sendAction('hidePicker');
}, (err) => {
let errors = get(this, 'errors') || [];
errors.push(`${ err.statusText }: ${ err.body.message }`);
setProperties(this, { errors, });
cb();
});
},
},
imageChanged: observer('config.image', function() {
const image = get(this, 'config.image');
if ( image === 'rancheros' ) {
set(this, 'config.sshUser', 'rancher');
} else if ( image.startsWith('coreos') ) {
set(this, 'config.sshUser', 'core');
} else {
set(this, 'config.sshUser', 'root');
}
}),
tagsDidChange: observer('tags', function() {
set(this, 'config.tags', get(this, 'tags').join(','));
}),
filteredSizeChoices: computed('config.region', function(){
let region = get(this, 'regionChoices').findBy('slug', get(this, 'config.region'));
let sizes = get(this, 'sizeChoices');
let out = sizes.filter((size) => {
return region.sizes.indexOf(size.slug) >= 0;
});
return out;
}),
bootstrap() {
let config = get(this, 'globalStore').createRecord({
type: 'digitaloceanConfig',
size: '2gb',
region: 'nyc3',
image: 'ubuntu-16-04-x64',
sshUser: 'root'
});
const model = get(this, 'model');
set(model, 'digitaloceanConfig', config);
},
apiRequest(command, opt, out) {
opt = opt || {};
let url = `${ get(this, 'app.proxyEndpoint') }/`;
if ( opt.url ) {
url += opt.url.replace(/^http[s]?\/\//, '');
} else {
url += `${ DIGITALOCEAN_API }/${ command }`;
url = addQueryParam(url, 'per_page', opt.per_page || 100);
url = addQueryParams(url, opt.params || {});
}
return fetch(url, {
headers: {
'Accept': 'application/json',
'X-Api-Auth-Header': `Bearer ${ get(this, 'config.accessToken') }`,
},
}).then((res) => {
let body = res.body;
if ( out ) {
out[command].pushObjects(body[command]);
} else {
out = body;
}
// De-paging
if ( body && body.links && body.links.pages && body.links.pages.next ) {
opt.url = body.links.pages.next;
return this.apiRequest(command, opt, out).then(() => {
return out;
});
} else {
return out;
}
});
}
});