import Component from '@ember/component' import ClusterDriver from 'shared/mixins/cluster-driver'; import layout from './template'; import { get, set, setProperties, computed, observer } from '@ember/object'; import { inject as service } from '@ember/service'; import { hash } from 'rsvp'; const NODE_POOL_HEADERS = [ { name: 'label', sort: ['label'], translationKey: 'clusterNew.linodelke.nodePoolConfig.label' }, { name: 'priceMonthly', sort: ['price.monthly'], translationKey: 'clusterNew.linodelke.nodePoolConfig.monthly' }, { name: 'priceHourly', sort: ['price.hourly'], translationKey: 'clusterNew.linodelke.nodePoolConfig.hourly' }, { name: 'ram', sort: ['memoryGb'], translationKey: 'clusterNew.linodelke.nodePoolConfig.ram' }, { name: 'cpus', sort: ['vcpus'], translationKey: 'clusterNew.linodelke.nodePoolConfig.cpus' }, { name: 'storage', sort: ['diskGb'], translationKey: 'clusterNew.linodelke.nodePoolConfig.storage' }, { name: 'count', sort: ['count'], translationKey: 'clusterNew.linodelke.nodePoolConfig.count' }, ]; export default Component.extend(ClusterDriver, { intl: service(), linode: service(), layout, configField: 'lkeEngineConfig', step: 1, lanChanged: null, refresh: false, sortBy: '', descending: false, nodePoolHeaders: NODE_POOL_HEADERS, init() { this._super(...arguments); let config = get(this, 'cluster.lkeEngineConfig'); let configField = get(this, 'configField'); setProperties(this, { 'newTag': '', 'selectedNodePoolType': '', 'selectedNodePoolObj': {}, 'selectedNodePoolList': this.prefillSelectedNodePoolList(), }); if ( !config ) { config = this.get('globalStore').createRecord({ type: configField, name: '', label: '', description: '', accessToken: '', region: 'us-central', kubernetesVersion: '', tags: [], nodePools: [] }); set(this, 'cluster.lkeEngineConfig', config); } }, actions: { verifyAccessToken(cb) { const auth = { token: get(this, 'cluster.lkeEngineConfig.accessToken'), }; let errors = []; const intl = get(this, 'intl'); if (!auth.token) { errors.push(intl.t('clusterNew.linodelke.accessToken.required')); set(this, 'errors', errors); cb(false); } else { hash({ regions: this.linode.request(auth, 'regions'), nodeTypes: this.linode.request(auth, 'linode/types'), k8sVersions: this.linode.request(auth, 'lke/versions'), }).then((responses) => { setProperties(this, { errors: [], step: 2, regions: responses.regions.data.filter((region) => (region.status === 'ok' && region.capabilities.includes('Kubernetes'))), nodeTypes: responses.nodeTypes.data.filter((type) => (type.class !== 'nanode' && type.class !== 'gpu')), k8sVersions: responses.k8sVersions.data, }); // default to latest version of LKE set(this, 'config.kubernetesVersion', responses.k8sVersions.data[0].id) cb(true); }).catch((err) => { if (err && err.body && err.body.errors && err.body.errors[0]) { errors.push(`Error received from Linode: ${ err.body.errors[0].reason }`); } else { errors.push(`Error received from Linode`); } this.setProperties({ errors, }); cb(false); }); } }, verifyClusterConfig(cb) { // verify if tags are not null // if null replace with empty array const tags = get(this, 'cluster.lkeEngineConfig.tags'); if (!tags) { set(this, 'cluster.lkeEngineConfig.tags', []); } set(this, 'step', 3); cb(true); }, createCluster(cb) { if (this.verifyNodePoolConfig()) { this.send('driverSave', cb); } else { cb(false); } }, updateCluster(cb) { if (this.verifyNodePoolConfig()) { this.send('driverSave', cb); } else { cb(false); } }, cancelFunc(cb){ // probably should not remove this as its what every other driver uses to get back get(this, 'router').transitionTo('global-admin.clusters.index'); cb(true); }, // for tags addNewTag() { const tags = get(this, 'cluster.lkeEngineConfig.tags') || []; const newTag = get(this, 'newTag'); if (newTag) { tags.pushObject(newTag); set(this, 'cluster.lkeEngineConfig.tags', tags); set(this, 'newTag', ''); } }, deleteTag(idx) { const tags = get(this, 'cluster.lkeEngineConfig.tags') || []; set(this, 'cluster.lkeEngineConfig.tags', tags.filter((tag, index) => index !== idx)); }, // for node pools addSelectedNodePool() { const selectedNodePoolObj = get(this, 'selectedNodePoolObj'); const selectedNodePoolList = get(this, 'selectedNodePoolList'); if (selectedNodePoolObj.id) { // add to list selectedNodePoolList.pushObject(selectedNodePoolObj); // clear selected set(this, 'selectedNodePoolType', ''); set(this, 'selectedNodePoolObj', {}); } }, deleteNodePool(id) { const selectedNodePoolList = get(this, 'selectedNodePoolList'); set(this, 'selectedNodePoolList', selectedNodePoolList.filter((n) => n.id !== id)) } }, // For languages clusterNameChanged: observer('cluster.name', function() { const clusterName = get(this, 'cluster.name'); setProperties(this, { 'cluster.lkeEngineConfig.name': clusterName, 'cluster.lkeEngineConfig.label': clusterName }); }), clusterDescriptionChanged: observer('cluster.description', function() { const clusterDescription = get(this, 'cluster.description'); set(this, 'cluster.lkeEngineConfig.description', clusterDescription); }), setSelectedNodePoolObj: observer('selectedNodePoolType', async function() { const nodePoolTypes = await get(this, 'nodeTypes'); const selectedNodePoolType = get(this, 'selectedNodePoolType'); if (selectedNodePoolType) { const ans = nodePoolTypes.find((np) => np.id === selectedNodePoolType); set(this, 'selectedNodePoolObj', { ...ans, count: 1, memoryGb: ans.memory / 1024, diskGb: ans.disk / 1024 }); } else { set(this, 'selectedNodePoolObj', {}); } }), setNodePools: observer('selectedNodePoolList.@each.count', function() { const selectedNodePoolList = get(this, 'selectedNodePoolList'); const nodePools = selectedNodePoolList.map((np) => { return `${ np.id }=${ np.count }` }) set(this, 'cluster.lkeEngineConfig.nodePools', nodePools); }), // to prefil selected node pool list for edit mode prefillSelectedNodePoolListObserver: observer('nodeTypes.[]', function() { this.prefillSelectedNodePoolList(); }), // Any computed properties or custom logic can go here // for region choises regionChoises: computed('regions', async function() { const ans = await get(this, 'regions'); return ans.map((e) => { return { label: e.id, value: e.id } }); }), // for kubernetes version k8sVersionChoises: computed('k8sVersions.[]', function() { const k8sVersions = get(this, 'k8sVersions'); return k8sVersions.map((v) => { return { label: v.id, value: v.id } }) }), // for node pool choises nodePoolChoises: computed('nodeTypes.[]', 'selectedNodePoolList.[]', async function() { const intl = get(this, 'intl'); const ans = await get(this, 'nodeTypes'); const filteredAns = ans.filter((np) => { // filter out the already selected node pools const selectedNodePoolList = get(this, 'selectedNodePoolList'); const fnd = selectedNodePoolList.find((snp) => snp.id === np.id); if (fnd) { return false; } else { return true; } }).map((np) => { return { label: np.label, value: np.id } }); return [{ label: intl.t('clusterNew.linodelke.nodePools.placeholder'), value: '' }, ...filteredAns]; }), // Add custom validation beyond what can be done from the config API schema validate() { // Get generic API validation errors this._super(); var errors = get(this, 'errors') || []; if ( !get(this, 'cluster.name') ) { errors.push('Name is required'); } // Add more specific errors // Check something and add an error entry if it fails: // if ( parseInt(get(this, 'config.memorySize'), defaultRadix) < defaultBase ) { // errors.push('Memory Size must be at least 1024 MB'); // } // Set the array of errors for display, // and return true if saving should continue. if ( get(errors, 'length') ) { set(this, 'errors', errors); return false; } else { set(this, 'errors', null); return true; } }, verifyNodePoolConfig() { const intl = get(this, 'intl'); const selectedNodePoolList = get(this, 'selectedNodePoolList'); const errors = []; if (selectedNodePoolList.length === 0) { errors.push(intl.t('clusterNew.linodelke.nodePools.required')); set(this, 'errors', errors); return false; } else { const fnd = selectedNodePoolList.find((np) => np.count <= 0); if (fnd) { errors.push(intl.t('clusterNew.linodelke.nodePools.countError')); set(this, 'errors', errors); return false; } return true; } }, async prefillSelectedNodePoolList() { const nodePools = get(this, 'cluster.lkeEngineConfig.nodePools'); const nodePoolTypes = await get(this, 'nodeTypes'); if (nodePools && nodePools.length) { set(this, 'selectedNodePoolList', nodePools.map((np) => { const [npId, cnt] = np.split('='); const fnd = nodePoolTypes.find((npt) => npt.id === npId); if (fnd) { return { ...fnd, count: cnt }; } else { return { id: npId, count: cnt, label: npId }; } })); } else { set(this, 'selectedNodePoolList', []); } }, });