mirror of https://github.com/rancher/ui.git
521 lines
15 KiB
JavaScript
521 lines
15 KiB
JavaScript
import { alias } from '@ember/object/computed';
|
|
import {
|
|
setProperties, get, set, computed, observer
|
|
} from '@ember/object';
|
|
import { scheduleOnce } from '@ember/runloop';
|
|
import Component from '@ember/component';
|
|
import NodeDriver from 'shared/mixins/node-driver';
|
|
import layout from './template';
|
|
import { storageTypes, environments } from 'ui/utils/azure-choices';
|
|
import { inject as service } from '@ember/service';
|
|
import { randomStr } from 'shared/utils/util';
|
|
import { addQueryParams } from 'shared/utils/util';
|
|
import { hash } from 'rsvp';
|
|
|
|
const DRIVER = 'azure';
|
|
const CONFIG = 'azureConfig';
|
|
|
|
const IPCHOICES = [
|
|
{
|
|
'name': 'Static',
|
|
'value': 'staticPublicIp=true,noPublicIp=false'
|
|
},
|
|
{
|
|
'name': 'Dynamic',
|
|
'value': 'staticPublicIp=false,noPublicIp=false'
|
|
},
|
|
{
|
|
'name': 'None',
|
|
'value': 'staticPublicIp=true,noPublicIp=true'
|
|
},
|
|
];
|
|
|
|
const MANAGED = 'managed';
|
|
const UNMANAGED = 'unmanaged';
|
|
|
|
const DISK_CHOICES = [
|
|
{
|
|
label: 'nodeDriver.azure.managedDisks.unmanaged',
|
|
value: UNMANAGED
|
|
},
|
|
{
|
|
label: 'nodeDriver.azure.managedDisks.managed',
|
|
value: MANAGED
|
|
}
|
|
];
|
|
|
|
export default Component.extend(NodeDriver, {
|
|
intl: service(),
|
|
|
|
layout,
|
|
environments,
|
|
driverName: DRIVER,
|
|
publicIpChoices: IPCHOICES,
|
|
diskChoices: DISK_CHOICES,
|
|
managedDisks: UNMANAGED,
|
|
model: null,
|
|
openPorts: null,
|
|
publicIpChoice: null,
|
|
tags: null,
|
|
step: 1,
|
|
useAvailabilitySet: true,
|
|
azureCredentialSecret: null,
|
|
regions: [],
|
|
regionsLoading: true,
|
|
vmSizes: [],
|
|
vmSizesLoading: true,
|
|
cloudCredentialId: '',
|
|
config: alias(`model.${ CONFIG }`),
|
|
storageTypeChoices: storageTypes.sortBy('name'),
|
|
showVmAvailabilityZoneWarning: computed.gt('vmAvailabilityZoneWarning.length', 0),
|
|
showVmSizeAvailabilityWarning: computed.gt('vmSizeAvailabilityWarning.length', 0),
|
|
showVmSizeAcceleratedNetworkingWarning: computed.gt('vmSizeAcceleratedNetworkingWarning.length', 0),
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
|
|
const tagsString = get(this, 'config.tags');
|
|
|
|
if ( tagsString ) {
|
|
const array = tagsString.split(',');
|
|
const tags = {};
|
|
|
|
for (let i = 0; i < array.length - 1; i = i + 2) {
|
|
tags[array[i]] = array[i + 1];
|
|
}
|
|
|
|
set(this, 'tags', tags);
|
|
}
|
|
|
|
const availabilityZone = get(this, 'config.availabilityZone');
|
|
|
|
if ( availabilityZone ) {
|
|
set(this, 'useAvailabilitySet', false);
|
|
}
|
|
|
|
scheduleOnce('afterRender', this, this.setupComponent);
|
|
},
|
|
actions: {
|
|
finishAndSelectCloudCredential(cred) {
|
|
if (cred) {
|
|
set(this, 'primaryResource.cloudCredentialId', get(cred, 'id'));
|
|
}
|
|
},
|
|
|
|
initAzureData(cb) {
|
|
const cloudCredentialId = get(this, 'primaryResource.cloudCredentialId')
|
|
|
|
set(this, 'cloudCredentialId', cloudCredentialId)
|
|
|
|
this.fetchVmSizes()
|
|
this.fetchRegions()
|
|
setProperties(this, { 'step': 2, });
|
|
|
|
if (cb && typeof cb === 'function') {
|
|
cb();
|
|
}
|
|
},
|
|
},
|
|
diskTypeChanged: observer('managedDisks', function() {
|
|
set(this, 'config.managedDisks', get(this, 'managedDisks') === MANAGED);
|
|
}),
|
|
|
|
locationObserver: observer('config.location', function(){
|
|
// When the location changes, the VM sizes should
|
|
// be refetched because not all sizes are available
|
|
// in all regions.
|
|
this.fetchVmSizes()
|
|
}),
|
|
|
|
tagsObserver: observer('tags', function() {
|
|
const array = [];
|
|
const tags = get(this, 'tags') || {};
|
|
|
|
Object.keys(tags).forEach((key) => {
|
|
array.push(key);
|
|
array.push(tags[key]);
|
|
});
|
|
|
|
set(this, 'config.tags', array.join(','));
|
|
}),
|
|
|
|
ipChoiceObserver: observer('publicIpChoice', function() {
|
|
let publicIpChoice = get(this, 'publicIpChoice');
|
|
|
|
if (get(this, 'publicIpChoices').findBy('value', publicIpChoice).name === 'None') {
|
|
set(this, 'config.usePrivateIp', true);
|
|
}
|
|
}),
|
|
|
|
publicIpObserver: observer('publicIpChoice', function() {
|
|
let elChoice = get(this, 'publicIpChoice');
|
|
let choice = get(this, 'publicIpChoices').findBy('value', elChoice);
|
|
|
|
choice = choice.value.split(',');
|
|
|
|
choice.forEach((val) => {
|
|
let tmp = val.split('=');
|
|
|
|
set(this, `config.${ tmp[0] }`, tmp[1] === 'true' ? true : false);
|
|
});
|
|
}),
|
|
|
|
openPort: observer('openPorts', function() {
|
|
let str = (get(this, 'openPorts') || '').trim();
|
|
let ary = [];
|
|
|
|
if (str.length) {
|
|
ary = str.split(/\s*,\s*/);
|
|
}
|
|
|
|
set(this, 'config.openPort', ary);
|
|
}),
|
|
|
|
useAvailabilitySetObserver: observer('useAvailabilitySet', function() {
|
|
// If the user switches between availability sets and availability zones,
|
|
// the other value should be cleared out.
|
|
if (get(this, 'useAvailabilitySet')) {
|
|
set(this, 'config.availabilityZone', '');
|
|
} else {
|
|
set(this, 'config.availabilitySet', '');
|
|
}
|
|
}),
|
|
|
|
vmsWithAcceleratedNetworking: computed('vmSizes', function() {
|
|
return get(this, 'vmSizes').filter((vmData) => {
|
|
return vmData.AcceleratedNetworkingSupported;
|
|
});
|
|
}),
|
|
|
|
vmsWithoutAcceleratedNetworking: computed('vmSizes', function() {
|
|
return get(this, 'vmSizes').filter((vmData) => {
|
|
return !vmData.AcceleratedNetworkingSupported;
|
|
});
|
|
}),
|
|
|
|
selectedVmSizeExistsInSelectedRegion: computed('config.{location,size}', 'vmSizes', function() {
|
|
// If the user selects a region and then a VM size
|
|
// that does not exist in the region, the list of VM
|
|
// sizes will update, causing the selected VM size
|
|
// to disappear. A disappearing VM size seems like a
|
|
// bad UX, so this value allows the value to be
|
|
// added to the VM size dropdown, while an error message
|
|
// indicates that the size is invalid.
|
|
if (get(this, 'vmSizes').find((size) => {
|
|
return size.Name === get(this, 'config.size');
|
|
})) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}),
|
|
|
|
vmsWithAvailabilityZones: computed('vmSizes', function() {
|
|
return get(this, 'vmSizes').filter((vmData) => {
|
|
return vmData.AvailabilityZones.length > 0;
|
|
});
|
|
}),
|
|
|
|
|
|
availabilityZoneChoices: computed('config.{location,size}', 'regions', 'vmSizes', function() {
|
|
const vmData = get(this, 'vmSizes').find((vm) => {
|
|
return vm.Name === get(this, 'config.size')
|
|
})
|
|
|
|
if (vmData) {
|
|
return vmData.AvailabilityZones.map((zone) => {
|
|
return {
|
|
name: zone,
|
|
value: zone,
|
|
};
|
|
})
|
|
.sort((a, b) => {
|
|
return a.value - b.value;
|
|
})
|
|
}
|
|
|
|
return [];
|
|
}),
|
|
availabilityZonesAreUnavailable: computed('availabilityZoneChoices', function() {
|
|
return get(this, 'availabilityZoneChoices').length === 0;
|
|
}),
|
|
sizeChoices: computed('config.size', 'selectedVmSizeExistsInSelectedRegion', 'vmSizes', 'vmsWithAcceleratedNetworking', 'vmsWithoutAcceleratedNetworking', function() {
|
|
// example vmSize option from backend:
|
|
// {
|
|
// AcceleratedNetworkingSupported: false,
|
|
// AvailabilityZones: [],
|
|
// Name: "Basic_A0"
|
|
// }
|
|
const intl = window.l('service:intl');
|
|
|
|
const noAnLabel = intl.t('nodeDriver.azure.size.doesNotSupportAcceleratedNetworking');
|
|
const withAnLabel = intl.t('nodeDriver.azure.size.supportsAcceleratedNetworking');
|
|
const vmsWithAn = get(this, 'vmsWithAcceleratedNetworking');
|
|
const vmsWithoutAn = get(this, 'vmsWithoutAcceleratedNetworking');
|
|
let out = [{
|
|
kind: 'group',
|
|
name: withAnLabel,
|
|
value: withAnLabel,
|
|
disabled: true
|
|
}]
|
|
.concat(vmsWithAn)
|
|
.concat(
|
|
{
|
|
kind: 'group',
|
|
name: noAnLabel,
|
|
value: noAnLabel,
|
|
disabled: true
|
|
}
|
|
)
|
|
.concat(vmsWithoutAn)
|
|
|
|
out = out.map((vmData) => {
|
|
const { Name } = vmData;
|
|
|
|
if (vmData.kind === 'group') {
|
|
return vmData;
|
|
}
|
|
|
|
return {
|
|
label: Name,
|
|
value: Name,
|
|
disabled: vmData.disabled || false,
|
|
};
|
|
});
|
|
|
|
if (!get(this, 'selectedVmSizeExistsInSelectedRegion')) {
|
|
return out.concat({
|
|
label: get(this, 'config.size'),
|
|
value: get(this, 'config.size'),
|
|
disabled: true
|
|
});
|
|
}
|
|
|
|
return out
|
|
}),
|
|
privateSet: computed('publicIpChoice', 'publicIpChoices', function() {
|
|
let publicIpChoice = get(this, 'publicIpChoice');
|
|
|
|
if (publicIpChoice && get(this, 'publicIpChoices').findBy('value', publicIpChoice).name === 'None') {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}),
|
|
|
|
setUsePrivateIp: computed('publicIpChoice', 'publicIpChoices', function() {
|
|
let publicIpChoice = get(this, 'publicIpChoice');
|
|
|
|
if (publicIpChoice && get(this, 'publicIpChoices').findBy('value', publicIpChoice).name === 'None') {
|
|
return set(this, 'config.usePrivateIp', true);
|
|
}
|
|
|
|
return false;
|
|
}),
|
|
|
|
selectedVmSizeHasZones: computed('config.{location,size}', 'value.size', 'vmSizes', 'vmsWithAvailabilityZones', function() {
|
|
const dataForSelectedSize = this.vmsWithAvailabilityZones.filter((vmData) => {
|
|
const { Name } = vmData;
|
|
|
|
return Name === get(this, 'config.size');
|
|
});
|
|
|
|
if (dataForSelectedSize.length > 0) {
|
|
return dataForSelectedSize[0].AvailabilityZones.length > 0;
|
|
}
|
|
|
|
return false;
|
|
}),
|
|
|
|
selectedVmSizeSupportsAN: computed('config.{location,size}', 'vmSizes', 'vmsWithAcceleratedNetworking', function() {
|
|
const selectedSizeIsValid = !!this.vmsWithAcceleratedNetworking.find((vmData) => {
|
|
return get(this, 'config.size') === vmData.Name;
|
|
});
|
|
|
|
return selectedSizeIsValid;
|
|
}),
|
|
|
|
vmSizeAcceleratedNetworkingWarning: computed('config.{acceleratedNetworking,location,size}', 'selectedVmSizeSupportsAN', 'vmSizes.length', function() {
|
|
if (get(this, 'vmSizes.length') === 0) {
|
|
// Don't show the warning until the VM sizes are loaded
|
|
return '';
|
|
}
|
|
|
|
const intl = window.l('service:intl')
|
|
|
|
if (!this.selectedVmSizeSupportsAN && get(this, 'config.acceleratedNetworking')) {
|
|
return intl.t('nodeDriver.azure.size.selectedSizeAcceleratedNetworkingWarning');
|
|
}
|
|
|
|
return '';
|
|
}),
|
|
|
|
vmSizeAvailabilityWarning: computed('config.{location,size}', 'regions.length', 'selectedVmSizeExistsInSelectedRegion', 'vmSizes.length', function() {
|
|
if (get(this, 'regions.length') === 0) {
|
|
// Don't show the warning until the regions are loaded
|
|
return '';
|
|
}
|
|
if (get(this, 'vmSizes.length') === 0) {
|
|
// Don't show the warning until the VM sizes are loaded
|
|
return '';
|
|
}
|
|
const intl = window.l('service:intl')
|
|
|
|
if (!get(this, 'selectedVmSizeExistsInSelectedRegion')) {
|
|
return intl.t('nodeDriver.azure.size.availabilityWarning');
|
|
}
|
|
|
|
return ''
|
|
}),
|
|
|
|
vmAvailabilityZoneWarning: computed('config.{location,size}', 'selectedVmSizeHasZones', 'useAvailabilitySet', 'value.size', 'vmSizes.length', 'vmsWithAvailabilityZones.length', function() {
|
|
if (this.useAvailabilitySet) {
|
|
return '';
|
|
}
|
|
if (get(this, 'vmSizes.length') === 0) {
|
|
// Don't show the warning until the VM sizes are loaded
|
|
return '';
|
|
}
|
|
|
|
const intl = window.l('service:intl')
|
|
|
|
if (this.vmsWithAvailabilityZones.length === 0) {
|
|
/**
|
|
* Show UI warning: Availability zones are not supported in the selected
|
|
* region. Please select a different region or use an
|
|
* availability set instead.
|
|
*/
|
|
return intl.t('nodeDriver.azure.size.regionDoesNotSupportAzs');
|
|
}
|
|
|
|
if (this.vmsWithAvailabilityZones.length > 0 && !this.selectedVmSizeHasZones) {
|
|
/**
|
|
* Show UI warning: The selected region does not support availability
|
|
* zones for the selected VM size. Please select a
|
|
* different region or VM size.
|
|
*/
|
|
return intl.t('nodeDriver.azure.size.regionSupportsAzsButNotThisSize');
|
|
}
|
|
|
|
return '';
|
|
}),
|
|
|
|
fetchRegions(){
|
|
const store = get(this, 'globalStore')
|
|
|
|
const regions = addQueryParams('/meta/aksLocations', { cloudCredentialId: this.cloudCredentialId })
|
|
|
|
const aksRequest = {
|
|
regions: store.rawRequest({
|
|
url: regions,
|
|
method: 'GET',
|
|
})
|
|
}
|
|
|
|
hash(aksRequest).then((resp) => {
|
|
const { regions } = resp;
|
|
|
|
setProperties(this, {
|
|
regions: regions?.body || [],
|
|
regionsLoading: false
|
|
});
|
|
}).catch((xhr) => {
|
|
const err = xhr.body?.message || xhr.body?.code || xhr.body?.error;
|
|
|
|
setProperties(this, { errors: [err], });
|
|
})
|
|
},
|
|
|
|
fetchVmSizes(){
|
|
const store = get(this, 'globalStore')
|
|
|
|
const vmSizes = addQueryParams('/meta/aksVMSizesV2', {
|
|
cloudCredentialId: this.cloudCredentialId,
|
|
region: get(this, 'config.location'),
|
|
});
|
|
|
|
const aksRequest = {
|
|
vmSizes: store.rawRequest({
|
|
url: vmSizes,
|
|
method: 'GET',
|
|
}),
|
|
}
|
|
|
|
hash(aksRequest).then((resp) => {
|
|
const { vmSizes } = resp;
|
|
|
|
setProperties(this, {
|
|
vmSizes: vmSizes?.body || [],
|
|
vmSizesLoading: false
|
|
});
|
|
}).catch((xhr) => {
|
|
const err = xhr.body.message || xhr.body.code || xhr.body.error;
|
|
|
|
setProperties(this, { errors: [err], });
|
|
});
|
|
},
|
|
|
|
bootstrap() {
|
|
let config = get(this, 'globalStore').createRecord({
|
|
type: CONFIG,
|
|
subscriptionId: '',
|
|
tags: '',
|
|
openPort: ['6443/tcp', '2379/tcp', '2380/tcp', '8472/udp', '4789/udp', '9796/tcp', '10256/tcp', '10250/tcp', '10251/tcp', '10252/tcp'],
|
|
});
|
|
|
|
set(this, `model.${ CONFIG }`, config);
|
|
},
|
|
|
|
initOpenPorts(ports) {
|
|
return ports ? ports.join(',') : '';
|
|
},
|
|
|
|
initPublicIpChoices(staticPublicIp, noPublicIp) {
|
|
if (staticPublicIp && noPublicIp) {
|
|
return get(this, 'publicIpChoices').findBy('name', 'None').value;
|
|
} else if (staticPublicIp && !noPublicIp) {
|
|
return get(this, 'publicIpChoices').findBy('name', 'Static').value;
|
|
} else {
|
|
return get(this, 'publicIpChoices').findBy('name', 'Dynamic').value;
|
|
}
|
|
},
|
|
|
|
validate() {
|
|
this._super();
|
|
let errors = get(this, 'errors') || [];
|
|
|
|
if ( !get(this, 'model.name') ) {
|
|
errors.push(this.intl.t('nodeDriver.nameError'));
|
|
}
|
|
|
|
if (!this.validateCloudCredentials()) {
|
|
errors.push(this.intl.t('nodeDriver.cloudCredentialError'))
|
|
}
|
|
|
|
|
|
if (errors.length) {
|
|
set(this, 'errors', errors.uniq());
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
|
|
|
|
|
|
setupComponent() {
|
|
setProperties(this, {
|
|
publicIpChoice: this.initPublicIpChoices(get(this, 'config.staticPublicIp'), get(this, 'config.noPublicIp')),
|
|
openPorts: this.initOpenPorts(get(this, 'config.openPort')),
|
|
managedDisks: get(this, 'config.managedDisks') ? MANAGED : UNMANAGED
|
|
});
|
|
|
|
if (!this.editing) {
|
|
set(this, 'config.nsg', `rancher-managed-${ randomStr(8, 8) }`);
|
|
}
|
|
},
|
|
|
|
});
|