fix: Update instance check for attach/detach volume

Update instance check for attach/detach volume

Change-Id: Ie6396b2b9c42d424d0396f9c840fb6182ebd45e5
This commit is contained in:
Jingwei.Zhang 2021-09-16 11:18:05 +08:00
parent f50df3da8d
commit 6f5816efe9
6 changed files with 68 additions and 63 deletions

View File

@ -15,12 +15,7 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import globalServerStore from 'stores/nova/instance'; import globalServerStore from 'stores/nova/instance';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import { import { allowAttachVolumeInstance } from 'resources/instance';
isActive,
isNotDeleting,
isNotLocked,
isIronicInstance,
} from 'resources/instance';
import { multiTip } from 'resources/volume'; import { multiTip } from 'resources/volume';
import { get as _get } from 'lodash'; import { get as _get } from 'lodash';
@ -61,13 +56,7 @@ export class AttachVolume extends ModalAction {
static allowed = (item, containerProps) => { static allowed = (item, containerProps) => {
const { isAdminPage } = containerProps; const { isAdminPage } = containerProps;
return Promise.resolve( return Promise.resolve(!isAdminPage && allowAttachVolumeInstance(item));
!isAdminPage &&
isActive(item) &&
isNotDeleting(item) &&
isNotLocked(item) &&
!isIronicInstance(item)
);
}; };
get formItems() { get formItems() {

View File

@ -17,12 +17,7 @@ import { VolumeStore } from 'stores/cinder/volume';
import globalServerStore from 'stores/nova/instance'; import globalServerStore from 'stores/nova/instance';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import { volumeStatus, isOsDisk } from 'resources/volume'; import { volumeStatus, isOsDisk } from 'resources/volume';
import { import { allowAttachVolumeInstance } from 'resources/instance';
isActive,
isNotLocked,
isNotDeleting,
isIronicInstance,
} from 'resources/instance';
export class DetachVolume extends ModalAction { export class DetachVolume extends ModalAction {
static id = 'detach-volume'; static id = 'detach-volume';
@ -66,16 +61,10 @@ export class DetachVolume extends ModalAction {
static policy = 'os_compute_api:os-volumes-attachments:delete'; static policy = 'os_compute_api:os-volumes-attachments:delete';
// static hasDataVolume = item => item.volumes_attached && item.volumes_attached.length > 1 static allowed = (item, containerProps) => {
const { isAdminPage } = containerProps;
// static allowed = item => Promise.resolve(isActive(item) && isNotDeleting(item) && isNotLocked(item) && this.hasDataVolume(item)) return Promise.resolve(!isAdminPage && allowAttachVolumeInstance(item));
static allowed = (item) => };
Promise.resolve(
isActive(item) &&
isNotDeleting(item) &&
isNotLocked(item) &&
!isIronicInstance(item)
);
get formItems() { get formItems() {
return [ return [

View File

@ -17,10 +17,7 @@ import { ModalAction } from 'containers/Action';
import { ServerStore } from 'stores/nova/instance'; import { ServerStore } from 'stores/nova/instance';
import globalVolumeStore from 'stores/cinder/volume'; import globalVolumeStore from 'stores/cinder/volume';
import { import {
isActive, allowAttachVolumeInstance,
isNotDeleting,
isNotLockedOrAdmin,
isIronicInstance,
instanceSelectTablePropsBackend, instanceSelectTablePropsBackend,
} from 'resources/instance'; } from 'resources/instance';
import { isAvailable, isMultiAttach } from 'resources/volume'; import { isAvailable, isMultiAttach } from 'resources/volume';
@ -51,12 +48,7 @@ export class Attach extends ModalAction {
return 'large'; return 'large';
} }
disabledInstance = (ins) => disabledInstance = (ins) => !allowAttachVolumeInstance(ins);
!isActive(ins) ||
!isNotDeleting(ins) ||
!isNotLockedOrAdmin(ins) ||
this.alreadyAttached(ins) ||
isIronicInstance(ins);
get defaultValue() { get defaultValue() {
const { name, id, size, volume_type } = this.item; const { name, id, size, volume_type } = this.item;
@ -78,7 +70,6 @@ export class Attach extends ModalAction {
Promise.resolve(isAvailable(item) || isMultiAttach(item)); Promise.resolve(isAvailable(item) || isMultiAttach(item));
get formItems() { get formItems() {
// const { multiattach } = this.item;
return [ return [
{ {
name: 'volume', name: 'volume',

View File

@ -16,7 +16,12 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import globalServerStore from 'stores/nova/instance'; import globalServerStore from 'stores/nova/instance';
import { ServerGroupInstanceStore } from 'stores/skyline/server-group-instance';
import { isInUse, isOsDisk } from 'resources/volume'; import { isInUse, isOsDisk } from 'resources/volume';
import {
instanceColumnsBackend,
allowAttachVolumeInstance,
} from 'resources/instance';
export class Detach extends ModalAction { export class Detach extends ModalAction {
static id = 'detach'; static id = 'detach';
@ -31,6 +36,8 @@ export class Detach extends ModalAction {
init() { init() {
this.store = globalServerStore; this.store = globalServerStore;
this.instanceStore = new ServerGroupInstanceStore();
this.getInstances();
} }
static get modalSize() { static get modalSize() {
@ -40,13 +47,15 @@ export class Detach extends ModalAction {
getModalSize() { getModalSize() {
return 'large'; return 'large';
} }
// get instances() {
// return this.store.list.data || [];
// }
// async getInstances() { get instances() {
// await this.store.fetchList({ limit: Infinity }); return this.instanceStore.list.data || [];
// } }
getInstances() {
const members = (this.item.attachments || []).map((it) => it.server_id);
this.instanceStore.fetchList({ members });
}
get defaultValue() { get defaultValue() {
const { name, size, volume_type } = this.item; const { name, size, volume_type } = this.item;
@ -66,6 +75,8 @@ export class Detach extends ModalAction {
item.attachments.length item.attachments.length
); );
disabledInstance = (ins) => !allowAttachVolumeInstance(ins);
get formItems() { get formItems() {
return [ return [
{ {
@ -79,11 +90,7 @@ export class Detach extends ModalAction {
label: t('Instance'), label: t('Instance'),
type: 'select-table', type: 'select-table',
required: true, required: true,
data: (this.item.attachments || []).map((s) => ({ data: this.instances,
...s,
name: s.server_name,
id: s.server_id,
})),
isMulti: true, isMulti: true,
filterParams: [ filterParams: [
{ {
@ -91,16 +98,9 @@ export class Detach extends ModalAction {
name: 'name', name: 'name',
}, },
], ],
columns: [ columns: instanceColumnsBackend,
{ isLoading: this.instanceStore.list.isLoading,
title: t('Name'), disabledFunc: this.disabledInstance,
dataIndex: 'name',
},
{
title: t('Attached To'),
dataIndex: 'device',
},
],
}, },
]; ];
} }

View File

@ -309,7 +309,6 @@ export const instanceColumnsBackend = [
render: (value, record) => ( render: (value, record) => (
<ImageType type={value} title={record.image_name} /> <ImageType type={value} title={record.image_name} />
), ),
stringify: (_, record) => record.image_name,
}, },
{ {
title: t('Fixed IP'), title: t('Fixed IP'),
@ -350,6 +349,18 @@ export const instanceColumnsBackend = [
dataIndex: 'flavor', dataIndex: 'flavor',
sorter: false, sorter: false,
}, },
{
title: t('Status'),
dataIndex: 'status',
sorter: false,
render: (value) => instanceStatus[value && value.toLowerCase()] || '-',
},
{
title: t('Locked'),
dataIndex: 'locked',
isHideable: true,
render: lockRender,
},
{ {
title: t('Created At'), title: t('Created At'),
dataIndex: 'created_at', dataIndex: 'created_at',
@ -379,6 +390,27 @@ export const instanceSelectTablePropsBackend = {
export const canCreateIronicByLicense = () => export const canCreateIronicByLicense = () =>
globalRootStore.checkLicense('ironic'); globalRootStore.checkLicense('ironic');
export const allowAttachVolumeInstance = (item) => {
const statusResult = checkStatus(
[
'active',
'paused',
'stopped',
'resized',
'soft-delete',
'shelved',
'shelved_offloaded',
],
item
);
return (
statusResult &&
isNotDeleting(item) &&
isNotLocked(item) &&
!isIronicInstance(item)
);
};
export const instanceStatusFilter = { export const instanceStatusFilter = {
label: t('Status'), label: t('Status'),
name: 'status', name: 'status',

View File

@ -27,12 +27,16 @@ export class ServerGroupInstanceStore extends Base {
}; };
} }
get groupArraySize() {
return 1;
}
async requestList(params, filters) { async requestList(params, filters) {
const { members, isServerGroup, all_projects } = filters; const { members, isServerGroup, all_projects } = filters;
if (members && isServerGroup && members.length === 0) { if (members && isServerGroup && members.length === 0) {
return []; return [];
} }
const memberArrs = groupArray(members, 10); const memberArrs = groupArray(members, this.groupArraySize);
const results = await Promise.all( const results = await Promise.all(
memberArrs.map((it) => { memberArrs.map((it) => {
const newParams = { ...params, uuid: it, all_projects }; const newParams = { ...params, uuid: it, all_projects };