Merge "feat: support quota info && check when resize instance"

This commit is contained in:
Zuul 2022-07-05 13:05:24 +00:00 committed by Gerrit Code Review
commit 03d34ba9a4
3 changed files with 121 additions and 6 deletions

View File

@ -22,8 +22,96 @@ import {
checkStatus, checkStatus,
isIronicInstance, isIronicInstance,
} from 'resources/nova/instance'; } from 'resources/nova/instance';
import globalProjectStore from 'stores/keystone/project';
import { isEmpty } from 'lodash';
import { getGiBValue, formatSize } from 'utils/index';
import FlavorSelectTable from '../components/FlavorSelectTable'; import FlavorSelectTable from '../components/FlavorSelectTable';
export async function fetchQuota(self) {
self.setState({
quota: {},
quotaLoading: true,
});
const result = await globalProjectStore.fetchProjectNovaQuota();
self.setState({
quota: result,
quotaLoading: false,
});
}
export const getQuota = (novaQuota) => {
if (isEmpty(novaQuota)) {
return {};
}
const { cores = {}, ram = {} } = novaQuota || {};
return {
cores,
ram,
};
};
export const getAdd = (self, flavor) => {
if (isEmpty(flavor)) {
return {};
}
const { vcpus: itemVcpus, ram: itemRam } = self.item.flavor_info || {};
const { vcpus, ram: flavorRam } = flavor || {};
const newVcpu = vcpus - itemVcpus;
const newRamGiB = getGiBValue(flavorRam - itemRam);
return {
vcpuAdd: newVcpu,
ramAdd: newRamGiB,
};
};
export const checkFlavorDisable = (flavor, self) => {
const { quotaLoading = true, quota } = self.state;
if (quotaLoading || isEmpty(quota)) {
return false;
}
const {
cores: { left },
ram: { left: ramLeft },
} = getQuota(quota);
const { vcpuAdd, ramAdd } = getAdd(self, flavor);
const vcpuOK = left === -1 || left >= vcpuAdd;
const ramOK = ramLeft === -1 || ramLeft >= ramAdd;
return !vcpuOK || !ramOK;
};
export const getQuotaInfo = (self) => {
const { quota = {}, quotaLoading, flavor = {} } = self.state;
if (quotaLoading || isEmpty(quota)) {
return [];
}
const { cores = {}, ram = {} } = getQuota(quota);
const { vcpuAdd = 0, ramAdd = 0 } = getAdd(self, flavor || {});
const cpuQuotaInfo = {
...cores,
add: vcpuAdd,
name: 'cpu',
title: t('CPU'),
};
const ramQuotaInfo = {
...ram,
add: ramAdd,
name: 'ram',
title: t('Memory (GiB)'),
type: 'line',
};
return [cpuQuotaInfo, ramQuotaInfo];
};
export const getFlavorLabel = (self) => {
const { flavor, flavor_info: { vcpus, ram } = {} } = self.item;
return `${flavor} (${t('VCPUs')}: ${vcpus}, ${t('Memory')}: ${formatSize(
ram,
2
)})`;
};
export class Resize extends ModalAction { export class Resize extends ModalAction {
static id = 'resize'; static id = 'resize';
@ -33,6 +121,7 @@ export class Resize extends ModalAction {
init() { init() {
this.store = globalFlavorStore; this.store = globalFlavorStore;
fetchQuota(this);
} }
get name() { get name() {
@ -71,8 +160,17 @@ export class Resize extends ModalAction {
); );
} }
get showQuota() {
return true;
}
get quotaInfo() {
return getQuotaInfo(this);
}
get defaultValue() { get defaultValue() {
const { name, flavor } = this.item; const { name } = this.item;
const flavor = getFlavorLabel(this);
const value = { const value = {
instance: name, instance: name,
flavor, flavor,
@ -82,7 +180,8 @@ export class Resize extends ModalAction {
static policy = 'os_compute_api:servers:resize'; static policy = 'os_compute_api:servers:resize';
static isActiveOrShutOff = (item) => checkStatus(['active', 'shutoff'], item); static isActiveOrShutOff = (item) =>
checkStatus(['active', 'shutoff'], item, false);
static allowed = (item, containerProps) => { static allowed = (item, containerProps) => {
const { isAdminPage } = containerProps; const { isAdminPage } = containerProps;
@ -94,6 +193,17 @@ export class Resize extends ModalAction {
); );
}; };
onFlavorChange = (flavor) => {
const { selectedRows = [] } = flavor || {};
this.setState({
flavor: selectedRows[0],
});
};
disabledFlavor = (flavor) => {
return checkFlavorDisable(flavor, this);
};
get formItems() { get formItems() {
const { flavor } = this.item; const { flavor } = this.item;
return [ return [
@ -114,7 +224,11 @@ export class Resize extends ModalAction {
label: t('Flavor'), label: t('Flavor'),
type: 'select-table', type: 'select-table',
component: ( component: (
<FlavorSelectTable flavor={flavor} onChange={this.onFlavorChange} /> <FlavorSelectTable
flavor={flavor}
onChange={this.onFlavorChange}
disabledFunc={this.disabledFlavor}
/>
), ),
required: true, required: true,
wrapperCol: { wrapperCol: {

View File

@ -329,7 +329,7 @@ export class FlavorSelectTable extends Component {
} }
render() { render() {
const { value } = this.props; const { value, disabledFunc } = this.props;
const isLoading = const isLoading =
this.settingStore.list.isLoading && this.flavorStore.list.isLoading; this.settingStore.list.isLoading && this.flavorStore.list.isLoading;
const props = { const props = {
@ -345,6 +345,7 @@ export class FlavorSelectTable extends Component {
], ],
value, value,
onChange: this.onChange, onChange: this.onChange,
disabledFunc,
}; };
return <SelectTable {...props} />; return <SelectTable {...props} />;
} }

View File

@ -152,11 +152,11 @@ export const isLocked = (instance) => !!instance.locked;
export const lockRender = (value) => (value ? lockIcon : unlockIcon); export const lockRender = (value) => (value ? lockIcon : unlockIcon);
export const checkStatus = (statusList = [], instance) => { export const checkStatus = (statusList = [], instance, checkState = true) => {
const { status, vm_state } = instance; const { status, vm_state } = instance;
return ( return (
statusList.includes(status.toLowerCase()) || statusList.includes(status.toLowerCase()) ||
(vm_state && statusList.includes(vm_state.toLowerCase())) (checkState && vm_state && statusList.includes(vm_state.toLowerCase()))
); );
}; };