feat: support cpu && mem quota info when create instance
1. Support cpu && mem quota info when create instance 2. Disable click next button when cpu && mem left quota is insufficient 3. Update StepForm to support disable click next/submit button Change-Id: Iae26d397debe67c44d8f80b6c5d85611a1cf67d5
This commit is contained in:
parent
10a951e088
commit
b6d2eb512f
@ -220,6 +220,14 @@ export default class BaseStepForm extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
get disableNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get disableSubmit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
setFormRefs() {
|
||||
this.formRefs = this.steps.map(() => React.createRef());
|
||||
}
|
||||
@ -297,7 +305,11 @@ export default class BaseStepForm extends React.Component {
|
||||
}
|
||||
const { title } = this.steps[current + 1];
|
||||
return (
|
||||
<Button type="primary" onClick={() => this.next()}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.next()}
|
||||
disabled={this.disableNext}
|
||||
>
|
||||
{`${t('Next')}: ${title}`}
|
||||
</Button>
|
||||
);
|
||||
@ -381,7 +393,11 @@ export default class BaseStepForm extends React.Component {
|
||||
{this.getPrevBtn()}
|
||||
{this.getNextBtn()}
|
||||
{current === this.steps.length - 1 && (
|
||||
<Button type="primary" onClick={this.onClickSubmit}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={this.onClickSubmit}
|
||||
disabled={this.disableSubmit}
|
||||
>
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
)}
|
||||
|
@ -22,12 +22,13 @@ import globalProjectStore from 'stores/keystone/project';
|
||||
import classnames from 'classnames';
|
||||
import { isEmpty, isFinite, isString } from 'lodash';
|
||||
import { getUserData } from 'resources/nova/instance';
|
||||
import { getGiBValue } from 'utils/index';
|
||||
import Notify from 'components/Notify';
|
||||
import styles from './index.less';
|
||||
import ConfirmStep from './ConfirmStep';
|
||||
import SystemStep from './SystemStep';
|
||||
import NetworkStep from './NetworkStep';
|
||||
import BaseStep from './BaseStep';
|
||||
import styles from './index.less';
|
||||
|
||||
export class StepCreate extends StepAction {
|
||||
static id = 'instance-create';
|
||||
@ -63,19 +64,28 @@ export class StepCreate extends StepAction {
|
||||
}
|
||||
|
||||
async getQuota() {
|
||||
await this.projectStore.fetchProjectQuota({
|
||||
project_id: this.currentProjectId,
|
||||
});
|
||||
await Promise.all([
|
||||
this.projectStore.fetchProjectNovaQuota(),
|
||||
this.projectStore.fetchProjectCinderQuota(),
|
||||
]);
|
||||
this.onCountChange(1);
|
||||
}
|
||||
|
||||
get quota() {
|
||||
const { instances = {} } = toJS(this.projectStore.quota) || {};
|
||||
const { limit = 10, used = 0 } = instances;
|
||||
if (limit === -1) {
|
||||
get disableNext() {
|
||||
return !!this.errorMsg;
|
||||
}
|
||||
|
||||
get disableSubmit() {
|
||||
return !!this.errorMsg;
|
||||
}
|
||||
|
||||
get instanceQuota() {
|
||||
const { instances: { left = 0 } = {} } =
|
||||
toJS(this.projectStore.novaQuota) || {};
|
||||
if (left === -1) {
|
||||
return Infinity;
|
||||
}
|
||||
return limit - used;
|
||||
return left;
|
||||
}
|
||||
|
||||
get name() {
|
||||
@ -150,7 +160,11 @@ export class StepCreate extends StepAction {
|
||||
}
|
||||
|
||||
get quotaInfo() {
|
||||
const { instances = {} } = toJS(this.projectStore.quota) || {};
|
||||
const {
|
||||
instances = {},
|
||||
cores = {},
|
||||
ram = {},
|
||||
} = toJS(this.projectStore.novaQuota) || {};
|
||||
const { limit } = instances || {};
|
||||
if (!limit) {
|
||||
return [];
|
||||
@ -165,6 +179,23 @@ export class StepCreate extends StepAction {
|
||||
// type: 'line',
|
||||
};
|
||||
|
||||
const { newCPU, newRam } = this.getFlavorInput();
|
||||
const cpuQuotaInfo = {
|
||||
...cores,
|
||||
add: newCPU,
|
||||
name: 'cpu',
|
||||
title: t('CPU'),
|
||||
type: 'line',
|
||||
};
|
||||
|
||||
const ramQuotaInfo = {
|
||||
...ram,
|
||||
add: newRam,
|
||||
name: 'ram',
|
||||
title: t('Memory (GiB)'),
|
||||
type: 'line',
|
||||
};
|
||||
|
||||
const volumeQuota = this.getVolumeQuota();
|
||||
const { totalNewCount, totalNewSize } = this.getVolumeInputMap();
|
||||
const volumeQuotaInfo = {
|
||||
@ -181,7 +212,13 @@ export class StepCreate extends StepAction {
|
||||
title: t('Volume Size'),
|
||||
type: 'line',
|
||||
};
|
||||
return [instanceQuotaInfo, volumeQuotaInfo, volumeSizeQuotaInfo];
|
||||
return [
|
||||
instanceQuotaInfo,
|
||||
cpuQuotaInfo,
|
||||
ramQuotaInfo,
|
||||
volumeQuotaInfo,
|
||||
volumeSizeQuotaInfo,
|
||||
];
|
||||
}
|
||||
|
||||
get errorText() {
|
||||
@ -203,27 +240,16 @@ export class StepCreate extends StepAction {
|
||||
|
||||
onCountChange = (value) => {
|
||||
const { data } = this.state;
|
||||
let msg = t('Quota: Project quotas sufficient resources can be created');
|
||||
let status = 'success';
|
||||
if (isFinite(this.quota) && value > this.quota) {
|
||||
msg = t(
|
||||
'Quota: Insufficient quota to create resources, please adjust resource quantity or quota(left { quota }, input { input }).',
|
||||
{ quota: this.quota, input: value }
|
||||
);
|
||||
status = 'error';
|
||||
}
|
||||
this.msg = msg;
|
||||
this.setState({
|
||||
data: {
|
||||
...data,
|
||||
count: value,
|
||||
},
|
||||
status,
|
||||
});
|
||||
};
|
||||
|
||||
getVolumeQuota() {
|
||||
const quotaAll = toJS(this.projectStore.quota) || {};
|
||||
const quotaAll = toJS(this.projectStore.cinderQuota) || {};
|
||||
const result = {};
|
||||
Object.keys(quotaAll).forEach((key) => {
|
||||
if (key.includes('volumes') || key.includes('gigabytes')) {
|
||||
@ -233,11 +259,11 @@ export class StepCreate extends StepAction {
|
||||
return result;
|
||||
}
|
||||
|
||||
getVolumeQuotaMsg(value, quota, name) {
|
||||
if (!quota || quota.limit === -1) {
|
||||
getQuotaMessage(value, quota, name) {
|
||||
const { left = 0 } = quota || {};
|
||||
if (left === -1) {
|
||||
return '';
|
||||
}
|
||||
const left = quota.limit - quota.in_use;
|
||||
if (value > left) {
|
||||
return t(
|
||||
'Insufficient {name} quota to create resources(left { quota }, input { input }).',
|
||||
@ -292,7 +318,7 @@ export class StepCreate extends StepAction {
|
||||
const { totalNewCount, totalNewSize, newCountMap, newSizeMap } =
|
||||
this.getVolumeInputMap();
|
||||
const quotaAll = this.getVolumeQuota();
|
||||
const totalCountMsg = this.getVolumeQuotaMsg(
|
||||
const totalCountMsg = this.getQuotaMessage(
|
||||
totalNewCount,
|
||||
quotaAll.volumes,
|
||||
t('volume')
|
||||
@ -300,7 +326,7 @@ export class StepCreate extends StepAction {
|
||||
if (totalCountMsg) {
|
||||
return totalCountMsg;
|
||||
}
|
||||
const totalSizeMsg = this.getVolumeQuotaMsg(
|
||||
const totalSizeMsg = this.getQuotaMessage(
|
||||
totalNewSize,
|
||||
quotaAll.gigabytes,
|
||||
t('volume gigabytes')
|
||||
@ -309,7 +335,7 @@ export class StepCreate extends StepAction {
|
||||
return totalSizeMsg;
|
||||
}
|
||||
Object.keys(newCountMap).forEach((key) => {
|
||||
const countMsg = this.getVolumeQuotaMsg(
|
||||
const countMsg = this.getQuotaMessage(
|
||||
newCountMap[key],
|
||||
quotaAll[`volumes_${key}`],
|
||||
t('volume type {type}', { type: key })
|
||||
@ -322,7 +348,7 @@ export class StepCreate extends StepAction {
|
||||
return msg;
|
||||
}
|
||||
Object.keys(newSizeMap).forEach((key) => {
|
||||
const sizeMsg = this.getVolumeQuotaMsg(
|
||||
const sizeMsg = this.getQuotaMessage(
|
||||
newSizeMap[key],
|
||||
quotaAll[`gigabytes_${key}`],
|
||||
t('volume type {type} gigabytes', { type: key })
|
||||
@ -334,20 +360,48 @@ export class StepCreate extends StepAction {
|
||||
return msg;
|
||||
}
|
||||
|
||||
getFlavorInput() {
|
||||
const { data } = this.state;
|
||||
const { flavor = {}, count = 1 } = data;
|
||||
const { selectedRows = [] } = flavor;
|
||||
const { vcpus = 0, ram = 0 } = selectedRows[0] || {};
|
||||
const ramGiB = getGiBValue(ram);
|
||||
const newCPU = vcpus * count;
|
||||
const newRam = ramGiB * count;
|
||||
return {
|
||||
newCPU,
|
||||
newRam,
|
||||
};
|
||||
}
|
||||
|
||||
checkFlavorQuota() {
|
||||
const { newCPU, newRam } = this.getFlavorInput();
|
||||
const { cores = {}, ram = {} } = this.projectStore.novaQuota;
|
||||
const { left = 0 } = cores || {};
|
||||
const { left: leftRam = 0 } = ram || {};
|
||||
if (left !== -1 && left < newCPU) {
|
||||
return this.getQuotaMessage(newCPU, cores, t('CPU'));
|
||||
}
|
||||
if (leftRam !== -1 && leftRam < newRam) {
|
||||
return this.getQuotaMessage(newRam, ram, t('Memory'));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
get badgeStyle() {
|
||||
return { marginTop: 8, marginBottom: 8, marginLeft: 10, maxWidth: 600 };
|
||||
}
|
||||
|
||||
renderBadge() {
|
||||
const { status = 'success' } = this.state;
|
||||
const flavorMsg = this.checkFlavorQuota();
|
||||
const volumeMsg = this.checkVolumeQuota();
|
||||
if (!volumeMsg && status === 'success') {
|
||||
if (!flavorMsg && !volumeMsg) {
|
||||
this.status = 'success';
|
||||
this.errorMsg = '';
|
||||
return null;
|
||||
}
|
||||
this.status = 'error';
|
||||
const msg = status === 'error' ? this.msg : volumeMsg;
|
||||
const msg = flavorMsg || volumeMsg;
|
||||
if (this.errorMsg !== msg) {
|
||||
$message.error(msg);
|
||||
}
|
||||
@ -371,8 +425,8 @@ export class StepCreate extends StepAction {
|
||||
max:
|
||||
sourceValue === 'bootableVolume'
|
||||
? 1
|
||||
: isFinite(this.quota)
|
||||
? this.quota
|
||||
: isFinite(this.instanceQuota)
|
||||
? this.instanceQuota
|
||||
: 100,
|
||||
precision: 0,
|
||||
onChange: this.onCountChange,
|
||||
|
@ -258,14 +258,10 @@ export class ProjectStore extends Base {
|
||||
] = await Promise.all(promiseArr);
|
||||
this.isSubmitting = false;
|
||||
const { quota_set: novaQuota } = novaResult;
|
||||
const { ram } = novaQuota;
|
||||
const { quota_set: cinderQuota = {} } = cinderResult || {};
|
||||
const { quota: neutronQuota } = neutronResult;
|
||||
const { quota_set: shareQuota = {} } = shareResult || {};
|
||||
novaQuota.ram = {
|
||||
in_use: getGiBValue(ram.in_use),
|
||||
limit: ram.limit === -1 ? ram.limit : getGiBValue(ram.limit),
|
||||
};
|
||||
this.updateNovaQuota(novaQuota);
|
||||
const renameShareQuota = Object.keys(shareQuota).reduce((pre, cur) => {
|
||||
const key = !cur.includes('share') ? `share_${cur}` : cur;
|
||||
pre[key] = shareQuota[cur];
|
||||
@ -462,6 +458,16 @@ export class ProjectStore extends Base {
|
||||
return limit - used - reserved;
|
||||
};
|
||||
|
||||
updateNovaQuota = (quota) => {
|
||||
const { ram: { limit = 0, in_use = 0, reserved = 0 } = {} } = quota || {};
|
||||
quota.ram = {
|
||||
in_use: getGiBValue(in_use),
|
||||
limit: limit === -1 ? limit : getGiBValue(limit),
|
||||
reserved: getGiBValue(reserved),
|
||||
};
|
||||
return quota;
|
||||
};
|
||||
|
||||
updateQuotaData = (quota) => {
|
||||
const newData = JSON.parse(JSON.stringify(quota));
|
||||
Object.keys(newData).forEach((it) => {
|
||||
@ -479,6 +485,7 @@ export class ProjectStore extends Base {
|
||||
async fetchProjectNovaQuota() {
|
||||
const result = await this.novaQuotaClient.detail(this.currentProjectId);
|
||||
const { quota_set: quota } = result;
|
||||
this.updateNovaQuota(quota);
|
||||
const novaQuota = this.updateQuotaData(quota);
|
||||
this.novaQuota = novaQuota;
|
||||
return novaQuota;
|
||||
|
Loading…
Reference in New Issue
Block a user