mirror of https://github.com/rancher/dashboard.git
277 lines
7.6 KiB
JavaScript
277 lines
7.6 KiB
JavaScript
import { sortBy } from '@shell/utils/sort';
|
|
import { randomStr } from '@shell/utils/string';
|
|
import { FetchHttpHandler } from '@smithy/fetch-http-handler';
|
|
import { isArray, addObjects } from '@shell/utils/array';
|
|
|
|
export const state = () => {
|
|
return {
|
|
instanceTypes: [],
|
|
clientInfo: null
|
|
};
|
|
};
|
|
|
|
class Handler {
|
|
constructor(cloudCredentialId, options) {
|
|
this.cloudCredentialId = (cloudCredentialId || '');
|
|
this.fetchHandler = new FetchHttpHandler(options);
|
|
}
|
|
|
|
async handle(httpRequest, options = {}) {
|
|
if (!httpRequest?.headers) {
|
|
httpRequest.headers = {};
|
|
}
|
|
|
|
httpRequest.headers['x-api-headers-restrict'] = 'Content-Length';
|
|
|
|
if (this.cloudCredentialId) {
|
|
httpRequest.headers['x-api-cattleauth-header'] = `awsv4 credID=${ this.cloudCredentialId }`;
|
|
} else if (httpRequest?.headers['authorization']) {
|
|
httpRequest.headers['x-api-auth-header'] = httpRequest.headers['authorization'];
|
|
}
|
|
|
|
delete httpRequest.headers['authorization'];
|
|
|
|
const originalContentType = httpRequest.headers['content-type'] ?? '';
|
|
|
|
httpRequest.headers['content-type'] = originalContentType ? `rancher:${ originalContentType }` : 'rancher:';
|
|
|
|
const endpoint = `/meta/proxy/`;
|
|
|
|
if (!httpRequest.path.startsWith(endpoint)) {
|
|
httpRequest.path = endpoint + httpRequest.hostname + httpRequest.path;
|
|
}
|
|
|
|
httpRequest.protocol = window.location.protocol;
|
|
httpRequest.hostname = window.location.hostname;
|
|
httpRequest.port = window.location.port;
|
|
|
|
return this.fetchHandler.handle(httpRequest, options);
|
|
}
|
|
}
|
|
|
|
function credentialDefaultProvider(accessKey, secretKey) {
|
|
return function() {
|
|
// The SDK will complain if these aren't set, so fill them with something
|
|
// even though the cloudCredential will be used eventually
|
|
const out = {
|
|
accessKeyId: accessKey || randomStr(),
|
|
secretAccessKey: secretKey || randomStr(),
|
|
};
|
|
|
|
return out;
|
|
};
|
|
}
|
|
|
|
export const getters = {
|
|
// You could override these to do something based on the user, maybe.
|
|
defaultRegion() {
|
|
return 'us-west-2';
|
|
},
|
|
|
|
defaultInstanceType() {
|
|
return 't3a.medium';
|
|
},
|
|
|
|
instanceTypes(state) {
|
|
return state.instanceTypes;
|
|
},
|
|
|
|
clientInfo(state) {
|
|
return state.clientInfo;
|
|
}
|
|
};
|
|
|
|
export const mutations = {
|
|
setInstanceTypes(state, { types, clientInfo }) {
|
|
state.instanceTypes = types;
|
|
state.clientInfo = clientInfo;
|
|
}
|
|
};
|
|
|
|
export const actions = {
|
|
ec2Lib() {
|
|
return import(/* webpackChunkName: "aws-ec2" */ '@aws-sdk/client-ec2');
|
|
},
|
|
|
|
eksLib() {
|
|
return import(/* webpackChunkName: "aws-eks" */ '@aws-sdk/client-eks');
|
|
},
|
|
|
|
kmsLib() {
|
|
return import(/* webpackChunkName: "aws-kms" */ '@aws-sdk/client-kms');
|
|
},
|
|
|
|
iamLib() {
|
|
return import(/* webpackChunkName: "aws-iam" */ '@aws-sdk/client-iam');
|
|
},
|
|
|
|
async ec2({ dispatch }, {
|
|
region, cloudCredentialId, accessKey, secretKey
|
|
}) {
|
|
const lib = await dispatch('ec2Lib');
|
|
|
|
const client = new lib.EC2({
|
|
region,
|
|
credentialDefaultProvider: credentialDefaultProvider(accessKey, secretKey),
|
|
requestHandler: new Handler(cloudCredentialId),
|
|
useDualstackEndpoint: true,
|
|
});
|
|
|
|
return client;
|
|
},
|
|
|
|
async eks({ dispatch }, {
|
|
region, cloudCredentialId, accessKey, secretKey
|
|
}) {
|
|
const lib = await dispatch('eksLib');
|
|
|
|
const client = new lib.EKS({
|
|
region,
|
|
credentialDefaultProvider: credentialDefaultProvider(accessKey, secretKey),
|
|
requestHandler: new Handler(cloudCredentialId),
|
|
useDualstackEndpoint: true,
|
|
});
|
|
|
|
return client;
|
|
},
|
|
|
|
async kms({ dispatch }, {
|
|
region, cloudCredentialId, accessKey, secretKey
|
|
}) {
|
|
const lib = await dispatch('kmsLib');
|
|
|
|
const client = new lib.KMS({
|
|
region,
|
|
credentialDefaultProvider: credentialDefaultProvider(accessKey, secretKey),
|
|
requestHandler: new Handler(cloudCredentialId),
|
|
useDualstackEndpoint: true,
|
|
});
|
|
|
|
return client;
|
|
},
|
|
|
|
async iam({ dispatch }, {
|
|
region, cloudCredentialId, accessKey, secretKey
|
|
}) {
|
|
const lib = await dispatch('iamLib');
|
|
|
|
const client = new lib.IAM({
|
|
region,
|
|
credentialDefaultProvider: credentialDefaultProvider(accessKey, secretKey),
|
|
requestHandler: new Handler(cloudCredentialId),
|
|
useDualstackEndpoint: true,
|
|
});
|
|
|
|
return client;
|
|
},
|
|
|
|
async describeInstanceTypes({
|
|
dispatch, rootGetters, state, commit
|
|
}, { client }) {
|
|
const cloudCredentialId = client?.config?.requestHandler?.cloudCredentialId;
|
|
const region = await client.config.region();
|
|
|
|
if (cloudCredentialId === rootGetters['aws/clientInfo']?.cloudCredentialId && region === rootGetters['aws/clientInfo']?.region) {
|
|
return rootGetters['aws/instanceTypes'];
|
|
}
|
|
const data = await dispatch('depaginateList', { client, cmd: 'describeInstanceTypes' });
|
|
|
|
const groups = (await import(/* webpackChunkName: "aws-data" */'@shell/assets/data/ec2-instance-groups.json')).default;
|
|
const list = [];
|
|
|
|
for ( const row of data ) {
|
|
const apiName = row.InstanceType;
|
|
const instanceClass = apiName.split('.')[0].toLowerCase();
|
|
const groupLabel = groups[instanceClass] || 'Unknown';
|
|
|
|
let storageSize = 0;
|
|
let storageUnit = 'GB';
|
|
let storageType = null;
|
|
const storageInfo = row.InstanceStorageInfo;
|
|
|
|
if ( storageInfo) {
|
|
storageSize = storageInfo.TotalSizeInGB;
|
|
const disk = storageInfo.Disks?.[0];
|
|
|
|
if ( storageInfo.NvmeSupport === 'supported' ) {
|
|
storageType = 'NVMe';
|
|
} else if ( disk?.Type === 'ssd' ) {
|
|
storageType = 'SSD';
|
|
} else if ( disk?.Type === 'hdd' ) {
|
|
storageType = 'HDD';
|
|
} else {
|
|
storageType = 'Unknown';
|
|
}
|
|
|
|
if ( storageSize > 1000 ) {
|
|
storageSize /= 1000;
|
|
storageUnit = 'TB';
|
|
}
|
|
} else {
|
|
// storageSize == 0 shows EBS-Only
|
|
}
|
|
|
|
list.push({
|
|
apiName,
|
|
currentGeneration: row.CurrentGeneration || false,
|
|
groupLabel,
|
|
instanceClass,
|
|
memoryBytes: row.MemoryInfo.SizeInMiB * 1024 * 1024,
|
|
supportedUsageClasses: row.SupportedUsageClasses,
|
|
supportedArchitectures: row.ProcessorInfo.SupportedArchitectures || [],
|
|
label: rootGetters['i18n/t']('cluster.machineConfig.aws.sizeLabel', {
|
|
apiName,
|
|
cpu: row.VCpuInfo.DefaultVCpus,
|
|
memory: row.MemoryInfo.SizeInMiB / 1024,
|
|
storageSize,
|
|
storageUnit,
|
|
storageType,
|
|
architecture: (row.ProcessorInfo.SupportedArchitectures || []).map((a) => (a === 'arm64' ? 'ARM' : a)).join(', ')
|
|
}),
|
|
});
|
|
}
|
|
|
|
const out = sortBy(list, ['currentGeneration:desc', 'groupLabel', 'instanceClass', 'memoryBytes', 'apiName']);
|
|
|
|
commit('setInstanceTypes', { types: out, clientInfo: { region, cloudCredentialId } });
|
|
|
|
return out;
|
|
},
|
|
|
|
async depaginateList(ctx, {
|
|
client, cmd, key, opt
|
|
}) {
|
|
let hasNext = true;
|
|
const out = [];
|
|
|
|
opt = opt || {};
|
|
|
|
while ( hasNext ) {
|
|
const res = await client[cmd](opt);
|
|
|
|
if ( !key ) {
|
|
key = Object.keys(res).find((x) => isArray(res[x]));
|
|
}
|
|
|
|
addObjects(out, res[key]);
|
|
if (res.NextToken) {
|
|
opt.NextToken = res.NextToken;
|
|
hasNext = true;
|
|
} else if (res.Marker) {
|
|
opt.Marker = res.Marker;
|
|
hasNext = true;
|
|
} else {
|
|
hasNext = false;
|
|
}
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
async defaultRegions() {
|
|
const data = (await import(/* webpackChunkName: "aws-data" */'@shell/assets/data/aws-regions.json')).default;
|
|
|
|
return data;
|
|
}
|
|
};
|