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

485 lines
14 KiB
JavaScript

import { alias } from '@ember/object/computed';
import { get, set, computed, observer } from '@ember/object';
import Component from '@ember/component';
import NodeDriver from 'shared/mixins/node-driver';
import layout from './template';
import { inject as service } from '@ember/service';
import C from 'shared/utils/constants';
const DRIVER = 'vmwarevsphere';
const CONFIG = 'vmwarevsphereConfig';
const VAPP_MODE_DISABLED = 'disabled';
const VAPP_MODE_AUTO = 'auto';
const VAPP_MODE_MANUAL = 'manual';
const CREATION_METHOD_DEPLOY_FROM_TEMPLATE_CONTENT_LIBRARY = 'deployFromTemplateContentLibrary';
const CREATION_METHOD_DEPLOY_FROM_TEMPLATE_DATA_CENTER = 'deployFromTemplateDataCenter';
const CREATION_METHOD_CLONE_AN_EXISTING_VIRTUAL_MACHINE = 'cloneAnExistingVirtualMachine';
const CREATION_METHOD_RANCHER_OS_ISO = 'rancherOsIso';
const stringsToParams = (params, str) => {
const index = str.indexOf('=');
if ( index > -1 ) {
params.push({
key: str.slice(0, index),
value: str.slice(index + 1),
});
}
return params;
};
const paramsToStrings = (strs, param) => {
if (param.value && param.key) {
strs.push(`${ param.key }=${ param.value }`);
}
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 networkToVappProperties = (props, network, i) => {
const n = i.toString();
props.push(
`guestinfo.interface.${ n }.ip.0.address=ip:${ network }`,
`guestinfo.interface.${ n }.ip.0.netmask=\${netmask:${ network }}`,
`guestinfo.interface.${ n }.route.0.gateway=\${gateway:${ network }}`
);
return props;
};
const getInitialVappMode = (c) => {
const vappProperty = c.vappProperty || []
if (
!c.vappIpprotocol &&
!c.vappIpallocationpolicy &&
!c.vappTransport &&
vappProperty.length === 0
) {
return VAPP_MODE_DISABLED;
}
const d = getDefaultVappOptions(c.network);
if (
c.vappIpprotocol === d.vappIpprotocol &&
c.vappIpallocationpolicy === d.vappIpallocationpolicy &&
c.vappTransport === d.vappTransport &&
vappProperty.length === d.vappProperty.length &&
vappProperty.join() === d.vappProperty.join()
) {
return VAPP_MODE_AUTO;
}
return VAPP_MODE_MANUAL;
};
export default Component.extend(NodeDriver, {
settings: service(),
intl: service(),
layout,
driverName: DRIVER,
model: {},
showEngineUrl: true,
initParamArray: null,
initVappArray: null,
initNetworkArray: [''],
vappMode: VAPP_MODE_DISABLED,
cache: {},
config: alias(`model.${ CONFIG }`),
init() {
this._super(...arguments);
this.initKeyValueParams('config.cfgparam', 'initParamArray');
this.initKeyValueParams('config.vappProperty', 'initVappArray');
this.initVappMode();
this.initCreationMethods();
this.initCustomAttributes();
},
actions: {
paramChanged(array) {
this.updateKeyValueParams('config.cfgparam', array);
},
vappPropertyChanged(array) {
this.updateKeyValueParams('config.vappProperty', array);
},
customAttributesChanged(array) {
set(this, 'config.customAttribute', array.map((a) => `${ a.key }=${ a.value }`));
},
finishAndSelectCloudCredential(credential) {
set(this, 'model.cloudCredentialId', get(credential, 'id'))
},
networkContentFilter(content, values) {
return content.filter((c) => values.indexOf(c.value) === -1);
},
tagContentFilter(content, values) {
const selectedOptions = values.map((v) => content.find((o) => o.id === v));
const selectedSingleCategories = selectedOptions
.filter((o) => o)
.map((o) => o.category)
.filter((c) => c.multipleCardinality === 'SINGLE');
return content.filter((c) => {
return selectedSingleCategories.indexOf(c.category) === -1
&& values.indexOf(c.id) === -1;
});
}
},
creationMethodObserver: observer('creationMethod', function() {
const creationType = get(this, 'creationMethod') === CREATION_METHOD_RANCHER_OS_ISO
? 'manual'
: 'clone';
set(this, 'config.creationType', creationType);
const isContentLibraryField = get(this, 'creationMethod') === CREATION_METHOD_DEPLOY_FROM_TEMPLATE_CONTENT_LIBRARY;
if (!isContentLibraryField && get(this, 'config.contentLibrary')) {
set(this, 'config.contentLibrary', undefined);
}
const isCloneFromMethod = get(this, 'creationMethod') === CREATION_METHOD_CLONE_AN_EXISTING_VIRTUAL_MACHINE
|| get(this, 'creationMethod') === CREATION_METHOD_DEPLOY_FROM_TEMPLATE_DATA_CENTER;
if (!isCloneFromMethod && get(this, 'config.cloneFrom')) {
set(this, 'config.cloneFrom', undefined);
}
}),
datacenterContent: computed('model.cloudCredentialId', async function() {
const options = await this.requestOptions('data-centers', get(this, 'model.cloudCredentialId'));
return this.mapPathOptionsToContent(options);
}),
tagContent: computed('model.cloudCredentialId', async function() {
const categoriesPromise = this.requestOptions('tag-categories', get(this, 'model.cloudCredentialId'));
const optionsPromise = this.requestOptions('tags', get(this, 'model.cloudCredentialId'));
const [categories, options] = await Promise.all([categoriesPromise, optionsPromise]);
return this.mapTagsToContent(options).map((option) => ({
...option,
category: categories.find((c) => c.name === option.category)
}));
}),
customAttributeContent: computed('model.cloudCredentialId', async function() {
const options = await this.requestOptions('custom-attributes', get(this, 'model.cloudCredentialId'));
return this.mapCustomAttributesToContent(options);
}),
hostContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'hosts',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapHostOptionsToContent(options);
}),
resourcePoolContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'resource-pools',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
dataStoreContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'data-stores',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
folderContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'folders',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapFolderOptionsToContent(options);
}),
networkContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'networks',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
contentLibraryContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'content-libraries',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
libraryTemplateContent: computed('config.contentLibrary', async function() {
const options = await this.requestOptions(
'library-templates',
get(this, 'model.cloudCredentialId'),
undefined,
get(this, 'config.contentLibrary')
);
return this.mapPathOptionsToContent(options);
}),
virtualMachineContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'virtual-machines',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
templateContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'templates',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
showRancherOsIso: computed('creationMethod', function() {
return get(this, 'creationMethod') === CREATION_METHOD_RANCHER_OS_ISO;
}),
showContentLibrary: computed('creationMethod', function() {
return get(this, 'creationMethod') === CREATION_METHOD_DEPLOY_FROM_TEMPLATE_CONTENT_LIBRARY;
}),
showVirtualMachine: computed('creationMethod', function() {
return get(this, 'creationMethod') === CREATION_METHOD_CLONE_AN_EXISTING_VIRTUAL_MACHINE;
}),
showTemplate: computed('creationMethod', function() {
return get(this, 'creationMethod') === CREATION_METHOD_DEPLOY_FROM_TEMPLATE_DATA_CENTER;
}),
bootstrap() {
let iso = get(this, `settings.${ C.SETTING.ENGINE_ISO_URL }`) || 'https://releases.rancher.com/os/latest/rancheros-vmware.iso';
let config = get(this, 'globalStore').createRecord({
type: CONFIG,
cpuCount: '2',
memorySize: '2048',
diskSize: '20000',
vcenterPort: '443',
network: [],
tag: [],
customAttribute: [],
cfgparam: ['disk.enableUUID=TRUE'],
boot2dockerUrl: iso,
datacenter: null,
vappIpprotocol: initialVAppOptions.vappIpprotocol,
vappIpallocationpolicy: initialVAppOptions.vappIpallocationpolicy,
vappTransport: initialVAppOptions.vappTransport,
vappProperty: initialVAppOptions.vappProperty,
});
set(this, `model.${ CONFIG }`, config);
},
initCreationMethods() {
set(this, 'creationMethodContent', [
{
label: this.intl.t(`nodeDriver.vmwarevsphere.creationMethod.${ CREATION_METHOD_DEPLOY_FROM_TEMPLATE_DATA_CENTER }`),
value: CREATION_METHOD_DEPLOY_FROM_TEMPLATE_DATA_CENTER
},
{
label: this.intl.t(`nodeDriver.vmwarevsphere.creationMethod.${ CREATION_METHOD_DEPLOY_FROM_TEMPLATE_CONTENT_LIBRARY }`),
value: CREATION_METHOD_DEPLOY_FROM_TEMPLATE_CONTENT_LIBRARY
},
{
label: this.intl.t(`nodeDriver.vmwarevsphere.creationMethod.${ CREATION_METHOD_CLONE_AN_EXISTING_VIRTUAL_MACHINE }`),
value: CREATION_METHOD_CLONE_AN_EXISTING_VIRTUAL_MACHINE
},
{
label: this.intl.t(`nodeDriver.vmwarevsphere.creationMethod.${ CREATION_METHOD_RANCHER_OS_ISO }`),
value: CREATION_METHOD_RANCHER_OS_ISO
},
]);
set(this, 'config.creationType', get(this, 'creationMethodOptions.firstObject.value'));
},
initKeyValueParams(pairsKey, paramsKey) {
set(this, paramsKey, (get(this, pairsKey) || []).reduce(stringsToParams, []));
},
updateKeyValueParams(pairsKey, params) {
set(this, pairsKey, params.reduce(paramsToStrings, []));
},
initVappMode() {
set(this, 'vappMode', getInitialVappMode(get(this, 'config')));
},
initCustomAttributes() {
set(this, 'initialCustomAttributes', get(this, 'config.customAttribute').map((v) => {
const [key, value] = v.split('=');
return {
key,
value,
};
}));
},
updateVappOptions(opts) {
set(this, 'config.vappIpprotocol', opts.vappIpprotocol);
set(this, 'config.vappIpallocationpolicy', opts.vappIpallocationpolicy);
set(this, 'config.vappTransport', opts.vappTransport);
set(this, 'config.vappProperty', opts.vappProperty);
this.initKeyValueParams('config.vappProperty', 'initVappArray');
},
willSave() {
const vappMode = get(this, 'vappMode')
if (vappMode === VAPP_MODE_DISABLED) {
this.updateVappOptions(initialVAppOptions);
} else if (vappMode === VAPP_MODE_AUTO) {
const network = get(this, 'config.network')
const defaultVappOptions = getDefaultVappOptions(network)
this.updateVappOptions(defaultVappOptions);
}
if ( !get(this, 'config.network') ) {
set(this, 'config.network', []);
}
return this._super(...arguments);
},
validate() {
this._super();
let errors = get(this, 'errors') || [];
if (!this.validateCloudCredentials()) {
errors.push(this.intl.t('nodeDriver.cloudCredentialError'))
}
if (errors.length) {
set(this, 'errors', errors.uniq());
return false;
}
return true;
},
async requestOptions(resource, cloudCredentialId, dataCenter, library) {
if (!cloudCredentialId) {
return [];
}
const queryParams = Object.entries({
cloudCredentialId,
dataCenter,
library
})
.filter((entry) => entry[1])
.map((entry) => `${ entry[0] }=${ entry[1] }`)
.join('&');
const url = `/meta/vsphere/${ resource }?${ queryParams }`;
return (await get(this, 'globalStore').rawRequest({
url,
method: 'GET'
})).body.data;
},
mapHostOptionsToContent(hostOptions) {
return this.mapPathOptionsToContent(hostOptions)
.map((c) => c.value === '' ? {
label: this.intl.t('nodeDriver.vmwarevsphere.hostOptions.any.label'),
value: c.value
} : c);
},
mapFolderOptionsToContent(folderOptions) {
return this.mapPathOptionsToContent(folderOptions)
.map((c) => c.value === '/' ? {
label: '/',
value: c.value
} : c);
},
mapPathOptionsToContent(pathOptions) {
return pathOptions.map((pathOption) => ({
label: pathOption.split('/').get('lastObject'),
value: pathOption
}));
},
mapCustomAttributesToContent(customAttributes) {
return customAttributes.map((customAttribute) => ({
label: customAttribute.name,
value: customAttribute.key.toString()
}));
},
mapTagsToContent(tags) {
return tags.map((tag) => ({
...tag,
label: `${ tag.category } / ${ tag.name }`,
value: tag.id
}));
}
});