mirror of https://github.com/rancher/ui.git
229 lines
7.4 KiB
JavaScript
229 lines
7.4 KiB
JavaScript
import { inject as service } from '@ember/service';
|
|
import Mixin from '@ember/object/mixin';
|
|
import { get, computed, setProperties } from '@ember/object';
|
|
import { convertToMillis, ucFirst, parseCamelcase } from 'shared/utils/util';
|
|
import { parseSi } from 'shared/utils/parse-unit';
|
|
import { requiredError } from 'shared/utils/util';
|
|
|
|
export default Mixin.create({
|
|
scope: service(),
|
|
|
|
preRequestsCpu: null,
|
|
preRequestsMemory: null,
|
|
clusterLevelMinCpu: 1000,
|
|
clusterLevelMinMemory: 1000,
|
|
projectLevelMinCpu: 500,
|
|
projectLevelMinMemory: 500,
|
|
|
|
insufficient: computed('scope.currentCluster.nodes', 'insufficientMemory', 'insufficientCpu', function() {
|
|
const allNodes = get(this, 'scope.currentCluster.nodes') || [];
|
|
|
|
if ( get(allNodes, 'length') === 0 ) {
|
|
return false;
|
|
}
|
|
|
|
return get(this, 'insufficientMemory') || get(this, 'insufficientCpu');
|
|
}),
|
|
|
|
leftCpu: computed('cluster.nodes.@each.{allocatable,requested}', function() {
|
|
const allNodes = get(this, 'cluster.nodes') || [];
|
|
|
|
if ( get(allNodes, 'length') === 0 ) {
|
|
return false;
|
|
}
|
|
|
|
const schedulableNodes = allNodes.filterBy('isUnschedulable', false);
|
|
|
|
let leftCpu = 0;
|
|
|
|
schedulableNodes.forEach((node) => {
|
|
const left = convertToMillis(get(node, 'allocatable.cpu') || '0') - convertToMillis(get(node, 'requested.cpu') || '0');
|
|
|
|
leftCpu += left;
|
|
});
|
|
|
|
return leftCpu;
|
|
}),
|
|
|
|
leftMemory: computed('cluster.nodes.@each.{allocatable,requested}', function() {
|
|
const allNodes = get(this, 'cluster.nodes') || [];
|
|
|
|
if ( get(allNodes, 'length') === 0 ) {
|
|
return false;
|
|
}
|
|
|
|
const schedulableNodes = allNodes.filterBy('isUnschedulable', false);
|
|
|
|
let leftMemory = 0;
|
|
|
|
schedulableNodes.forEach((node) => {
|
|
const left = (parseSi(get(node, 'allocatable.memory'), 1024) / 1048576) - (parseSi(get(node, 'requested.memory') || '0', 1024) / 1048576);
|
|
|
|
leftMemory += left;
|
|
});
|
|
|
|
return leftMemory;
|
|
}),
|
|
|
|
insufficientMemory: computed('preRequestsMemory', 'requestsMemory', 'leftMemory', function() {
|
|
const {
|
|
preRequestsMemory, requestsMemory, leftMemory, enabled, minMemory
|
|
} = this
|
|
|
|
if ( enabled ) {
|
|
return leftMemory <= parseInt(requestsMemory || 0, 10) - parseInt(preRequestsMemory || 0, 10);
|
|
} else {
|
|
return leftMemory <= minMemory;
|
|
}
|
|
}),
|
|
|
|
insufficientCpu: computed('preRequestsCpu', 'requestsCpu', 'leftCpu', function() {
|
|
const {
|
|
preRequestsCpu, requestsCpu, leftCpu, enabled, minCpu
|
|
} = this
|
|
|
|
if ( enabled ) {
|
|
return leftCpu <= parseInt(requestsCpu || 0, 10) - parseInt(preRequestsCpu || 0, 10);
|
|
} else {
|
|
return leftCpu <= minCpu;
|
|
}
|
|
}),
|
|
|
|
minCpu: computed('clusterLevelMinCpu', 'level', 'projectLevelMinCpu', 'requestsCpu', function() {
|
|
let cpu = parseInt(get(this, 'requestsCpu') || 0, 10);
|
|
|
|
if ( isNaN(cpu) ) {
|
|
cpu = 0;
|
|
}
|
|
|
|
return (get(this, 'level') === 'cluster' ? get(this, 'clusterLevelMinCpu') : get(this, 'projectLevelMinCpu')) + cpu;
|
|
}),
|
|
|
|
minMemory: computed('clusterLevelMinMemory', 'level', 'projectLevelMinMemory', 'requestsMemory', function() {
|
|
let memory = parseInt(get(this, 'requestsMemory') || 0, 10);
|
|
|
|
if ( isNaN(memory) ) {
|
|
memory = 0;
|
|
}
|
|
|
|
return (get(this, 'level') === 'cluster' ? get(this, 'clusterLevelMinMemory') : get(this, 'projectLevelMinMemory')) + memory;
|
|
}),
|
|
|
|
getComponentInsufficient(component, type, reservation) {
|
|
const allNodes = get(this, 'cluster.nodes') || [];
|
|
|
|
if ( get(allNodes, 'length') === 0 ) {
|
|
return false;
|
|
}
|
|
|
|
const maxLeft = get(this, `${ component }SchedulableNodes`).reduce((out, node) => {
|
|
let left
|
|
|
|
if (type === 'cpu') {
|
|
left = convertToMillis(get(node, `allocatable.${ type }`)) - convertToMillis(get(node, `requested.${ type }`) || '0');
|
|
} else if (type === 'memory') {
|
|
left = (parseSi(get(node, 'allocatable.memory'), 1024) / 1048576) - (parseSi(get(node, 'requested.memory') || '0', 1024) / 1048576);
|
|
}
|
|
|
|
return left > out ? left : out
|
|
}, 0)
|
|
|
|
const request = reservation ? reservation : get(this, `config.${ component }Request${ ucFirst(type) }`) || 0
|
|
|
|
return get(this, 'enabled') ? false : maxLeft <= request
|
|
},
|
|
|
|
getSchedulableNodes(component) {
|
|
const allNodes = get(this, 'cluster.nodes') || [];
|
|
|
|
const out = allNodes.filterBy('isUnschedulable', false)
|
|
.filter((node) => (get(this, `${ component }NodeSelectors`) || [])
|
|
.every((selector) => {
|
|
const labelValue = (get(node, 'labels') || {})[get(selector, 'key')];
|
|
|
|
if ( get(selector, 'value') === '' ) {
|
|
return labelValue !== undefined;
|
|
} else {
|
|
return get(selector, 'value') === labelValue;
|
|
}
|
|
}));
|
|
|
|
return out;
|
|
},
|
|
|
|
getComponentWarning(component, componentCpu, componentMemory, displayComponent, ) {
|
|
const insufficientCpu = get(this, `insufficient${ ucFirst(component) }Cpu`)
|
|
const insufficientMemory = get(this, `insufficient${ ucFirst(component) }Memory`)
|
|
const nodeSelectors = get(this, `${ component }NodeSelectors`) || []
|
|
const intl = get(this, 'intl')
|
|
|
|
const cpu = componentCpu ? componentCpu : get(this, `config.${ component }RequestCpu`)
|
|
const memory = componentMemory ? componentMemory : get(this, `config.${ component }RequestMemory`)
|
|
let prefix = 'clusterIstioPage.insufficientSize.selectors'
|
|
|
|
if (nodeSelectors.length === 0) {
|
|
prefix = 'clusterIstioPage.insufficientSize.workload'
|
|
} else {
|
|
const unsupportedSelectors = nodeSelectors.filter((n) => n.value === 'true' || n.value === 'false' || /^\d+$/g.test(n.value))
|
|
|
|
if (unsupportedSelectors.length > 0) {
|
|
return intl.t(`clusterIstioPage.insufficientSize.selectors.unsupported`, { component: displayComponent ? displayComponent : parseCamelcase(component), })
|
|
}
|
|
}
|
|
|
|
if (insufficientCpu && insufficientMemory) {
|
|
return intl.t(`${ prefix }.all`, {
|
|
cpu,
|
|
memory,
|
|
component: displayComponent ? displayComponent : parseCamelcase(component),
|
|
})
|
|
} else if (insufficientCpu) {
|
|
return intl.t(`${ prefix }.cpu`, {
|
|
cpu,
|
|
component: displayComponent ? displayComponent : parseCamelcase(component),
|
|
})
|
|
} else if (insufficientMemory) {
|
|
return intl.t(`${ prefix }.memory`, {
|
|
memory,
|
|
component: displayComponent ? displayComponent : parseCamelcase(component),
|
|
})
|
|
}
|
|
},
|
|
|
|
validateLimitAndRequest(component) {
|
|
const errors = [];
|
|
|
|
['requestCpu', 'limitCpu', 'requestMemory', 'limitMemory'].map((suffix) => {
|
|
const key = `config.${ component }${ ucFirst(suffix) }`
|
|
|
|
if (!get(this, key)) {
|
|
errors.pushObject(requiredError(`formReservation.${ suffix }.label`, { component: ucFirst(component) }))
|
|
}
|
|
})
|
|
|
|
return errors
|
|
},
|
|
|
|
updateCpuMemoryPreRequest() {
|
|
const answers = get(this, 'app.answers') || {};
|
|
const workloads = this.getEnalbedWorkloads(answers);
|
|
|
|
const preRequestsCpu = workloads.reduce((all, current) => {
|
|
const value = answers[`${ current }.resources.requests.cpu`]
|
|
|
|
return value ? all + convertToMillis(value) : all
|
|
}, 0)
|
|
|
|
const preRequestsMemory = workloads.reduce((all, current) => {
|
|
const value = answers[`${ current }.resources.requests.memory`]
|
|
|
|
return value ? all + parseSi(value) / 1048576 : all
|
|
}, 0)
|
|
|
|
setProperties(this, {
|
|
preRequestsCpu,
|
|
preRequestsMemory,
|
|
})
|
|
},
|
|
});
|