feat: support quota info when snapshot create volume

1. Support quota info when snapshot create volume
2. Disable click submit button when quota is insufficient

Change-Id: I81a3bde0f4bd7bdc403bea8176754c5dc5a32373
This commit is contained in:
Jingwei.Zhang 2022-06-29 15:38:34 +08:00
parent 78cb485068
commit b605ac01c4
3 changed files with 256 additions and 6 deletions

View File

@ -15,6 +15,14 @@
import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action';
import globalVolumeStore from 'stores/cinder/volume';
import {
getQuotaInfo,
checkQuotaDisable,
fetchQuota,
setCreateVolumeType,
onVolumeSizeChange,
onVolumeTypeChange,
} from 'resources/cinder/volume';
export class CreateVolume extends ModalAction {
static id = 'create';
@ -22,8 +30,9 @@ export class CreateVolume extends ModalAction {
static title = t('Create Volume');
init() {
this.volumeStore = globalVolumeStore;
this.store = globalVolumeStore;
this.getVolumeTypes();
fetchQuota(this, this.item.size);
}
get name() {
@ -34,6 +43,22 @@ export class CreateVolume extends ModalAction {
static allowed = () => Promise.resolve(true);
static get disableSubmit() {
return checkQuotaDisable();
}
static get showQuota() {
return true;
}
get showQuota() {
return true;
}
get quotaInfo() {
return getQuotaInfo(this);
}
get volumeTypeParams() {
return {};
}
@ -42,19 +67,21 @@ export class CreateVolume extends ModalAction {
const { volume_id: id } = this.item;
// eslint-disable-next-line no-unused-vars
const [_, volume] = await Promise.all([
this.volumeStore.fetchVolumeTypes(this.volumeTypeParams),
this.volumeStore.fetchDetail({ id }),
this.store.fetchVolumeTypes(this.volumeTypeParams),
this.store.fetchDetail({ id }),
]);
const { volume_type: volumeType } = volume;
const typeItem = this.volumeTypes.find((it) => it.label === volumeType);
if (typeItem) {
this.volumeType = typeItem.value;
setCreateVolumeType(volumeType);
}
this.updateFormValue('volume_type', this.volumeType);
this.updateDefaultValue();
}
get volumeTypes() {
return this.volumeStore.volumeTypes || [];
return this.store.volumeTypes || [];
}
get defaultValue() {
@ -94,6 +121,7 @@ export class CreateVolume extends ModalAction {
min: this.minSize,
extra: `${t('Min size')}: ${this.minSize}GiB`,
required: true,
onChange: onVolumeSizeChange,
},
{
name: 'more',
@ -107,6 +135,8 @@ export class CreateVolume extends ModalAction {
options: this.volumeTypes,
placeholder: t('Please select volume type'),
hidden: !more,
onChange: onVolumeTypeChange,
allowClear: false,
},
];
}

View File

@ -15,6 +15,9 @@
import React from 'react';
import { yesNoOptions } from 'utils/constants';
import { toLocalTimeFilter } from 'utils/index';
import globalProjectStore from 'stores/keystone/project';
import globalVolumeStore from 'stores/cinder/volume';
import { isEmpty } from 'lodash';
export const volumeStatus = {
available: t('Available'),
@ -338,3 +341,185 @@ export const getVolumeColumnsList = (self) => {
}
return columns;
};
// deal with quota
export function setCreateVolumeSize(value) {
globalVolumeStore.setCreateVolumeSize(value);
}
export function setCreateVolumeType(value) {
globalVolumeStore.setCreateVolumeType(value);
}
export function setCreateVolumeCount(value) {
globalVolumeStore.setCreateVolumeCount(value);
}
export async function fetchQuota(self, size) {
setCreateVolumeCount(1);
setCreateVolumeSize(size);
setCreateVolumeType('');
self.setState({
quota: {},
quotaLoading: true,
});
const result = await globalProjectStore.fetchProjectCinderQuota();
self.setState({
quota: result,
quotaLoading: false,
});
}
export const getQuota = (cinderQuota) => {
if (isEmpty(cinderQuota)) {
return {};
}
const { volumeTypeForCreate } = globalVolumeStore;
const { volumes = {}, gigabytes = {} } = cinderQuota || {};
const typeQuotaKey = `volumes_${volumeTypeForCreate}`;
const sizeQuotaKey = `gigabytes_${volumeTypeForCreate}`;
const typeQuota = (cinderQuota || {})[typeQuotaKey] || {};
const typeSizeQuota = (cinderQuota || {})[sizeQuotaKey] || {};
return {
volumes,
gigabytes,
typeQuota,
typeSizeQuota,
};
};
const getErrorMessage = ({ name, left, input }) => {
const error = t(
'Quota: Insufficient { name } quota to create resources, please adjust resource quantity or quota(left { left }, input { input }).',
{
name,
left,
input,
}
);
return error;
};
export const getAdd = (cinderQuota) => {
if (isEmpty(cinderQuota)) {
return {};
}
const { volumes, gigabytes, typeQuota, typeSizeQuota } =
getQuota(cinderQuota);
const { left = 0 } = volumes || {};
const { left: sizeLeft = 0, limit: sizeLimit } = gigabytes || {};
const { left: typeLeft = 0 } = typeQuota || {};
const { left: typeSizeLeft = 0, limit: typeSizeLimit } = typeSizeQuota || {};
const {
volumeSizeForCreate: size = 0,
volumeCountForCreate: count = 1,
volumeTypeForCreate: type = '',
} = globalVolumeStore;
const zero = {
add: 0,
addSize: 0,
};
const totalSize = size * count;
const create = {
add: count,
addSize: totalSize,
};
if (left >= 0 && left < count) {
const error = getErrorMessage({
name: t('volume'),
left,
input: count,
});
return { ...zero, error };
}
if (sizeLimit !== -1 && sizeLeft < totalSize) {
const error = getErrorMessage({
name: t('gigabytes'),
left: sizeLeft,
input: totalSize,
});
return { ...zero, error };
}
if (isEmpty(typeQuota)) {
return create;
}
if (typeLeft >= 0 && typeLeft < count) {
const error = getErrorMessage({
name: t('{name} type', { name: type }),
left: typeLeft,
input: count,
});
return { ...zero, error };
}
if (typeSizeLimit !== -1 && typeSizeLeft < totalSize) {
const error = getErrorMessage({
name: t('{name} type gigabytes', { name: type }),
left: typeSizeLeft,
input: totalSize,
});
return { ...zero, error };
}
return create;
};
export const getQuotaInfo = (self) => {
const { volumeTypeForCreate: name } = globalVolumeStore;
const { quota = {}, quotaLoading } = self.state;
if (quotaLoading || isEmpty(quota)) {
return [];
}
const {
volumes = {},
gigabytes = {},
typeQuota = {},
typeSizeQuota = {},
} = getQuota(quota);
const { add, addSize } = getAdd(quota);
const volumeData = {
...volumes,
add,
name: 'volume',
title: t('Volume'),
};
const sizeData = {
...gigabytes,
add: addSize,
name: 'gigabytes',
title: t('Gigabytes (GiB)'),
type: 'line',
};
if (!name) {
return [volumeData, sizeData];
}
const typeData = {
...typeQuota,
add,
name: 'type',
title: t('{name} type', { name }),
type: 'line',
};
const typeSizeData = {
...typeSizeQuota,
add: addSize,
name: 'typeSize',
title: t('{name} type gigabytes', { name }),
type: 'line',
};
return [volumeData, sizeData, typeData, typeSizeData];
};
export const checkQuotaDisable = () => {
const { cinderQuota = {} } = globalProjectStore;
const { add } = getAdd(cinderQuota);
return add === 0;
};
export const onVolumeSizeChange = (value) => {
setCreateVolumeSize(value);
};
export const onVolumeTypeChange = (value) => {
const { volumeTypes = [] } = globalVolumeStore;
const item = volumeTypes.find((it) => it.value === value);
setCreateVolumeType(item.label);
};

View File

@ -13,7 +13,6 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { isOsDisk } from 'resources/cinder/volume';
import { renderFilterMap } from 'utils/index';
import client from 'client';
import Base from 'stores/base';
@ -32,6 +31,15 @@ export class VolumeStore extends Base {
@observable
quotaSet = {};
@observable
volumeTypeForCreate = '';
@observable
volumeSizeForCreate = 0;
@observable
volumeCountForCreate = 1;
get client() {
return client.cinder.volumes;
}
@ -56,10 +64,15 @@ export class VolumeStore extends Base {
return this.skylineClient.extension.volumes(params);
}
isOsDisk(item) {
const { isOsDisk } = require('resources/cinder/volume');
return isOsDisk(item);
}
get mapper() {
return (volume) => ({
...volume,
disk_tag: isOsDisk(volume) ? 'os_disk' : 'data_disk',
disk_tag: this.isOsDisk(volume) ? 'os_disk' : 'data_disk',
description: volume.description || (volume.origin_data || {}).description,
delete_interval:
volume.metadata && volume.metadata.delete_interval
@ -214,6 +227,28 @@ export class VolumeStore extends Base {
}));
this.originalVolumeTypes = data || [];
}
@action
setCreateVolumeSize(size = 0) {
this.volumeSizeForCreate = size;
}
@action
setCreateVolumeType(type = '') {
this.volumeTypeForCreate = type;
}
@action
setCreateVolumeCount(count = 1) {
this.volumeCountForCreate = count;
}
@action
setCreateVolumeInfo({ size = 0, type = '', count = 1 } = {}) {
this.setCreateVolumeSize(size);
this.setCreateVolumeType(type);
this.setCreateVolumeCount(count);
}
}
const globalVolumeStore = new VolumeStore();