fix: Not show the data disk when creating vm by Instance snapshot
Not show the data disk when creating vm by Instance snapshot with system disk and data disk 1. fetch instanceSnapshotDataVolumes data when change instance snapshot 2. add Required Data Disk form item of BaseStep when create instance by snapshot 3. show instance snapshot data disk's info if instance snapshot has system disk and data disk 4. hide render default system disk when selecting Bootable Volume of Start Source's option Closes-Bug: #1992739 Change-Id: I3a1daa8845cc9f73b8ea8d0216d49ad858b7168b
This commit is contained in:
parent
27fb2b2db0
commit
fdd6dbb5e3
@ -1940,6 +1940,7 @@
|
||||
"Request ID": "Request ID",
|
||||
"Require": "Require",
|
||||
"Require(Need multithreading)": "Require(Need multithreading)",
|
||||
"Required Data Disk": "Required Data Disk",
|
||||
"Rescue": "Rescue",
|
||||
"Rescued": "Rescued",
|
||||
"Rescuing": "Rescuing",
|
||||
|
@ -1940,6 +1940,7 @@
|
||||
"Request ID": "请求ID",
|
||||
"Require": "强制",
|
||||
"Require(Need multithreading)": "Require(必须有多线程)",
|
||||
"Required Data Disk": "所需数据盘",
|
||||
"Rescue": "救援",
|
||||
"Rescued": "已救援",
|
||||
"Rescuing": "救援中",
|
||||
|
@ -34,6 +34,11 @@ import {
|
||||
import Base from 'components/Form';
|
||||
import InstanceVolume from 'components/FormItem/InstanceVolume';
|
||||
import { isGpuCategory } from 'resources/nova/flavor';
|
||||
import {
|
||||
volumeTypes,
|
||||
getDiskInfo,
|
||||
getInstanceSnapshotDataDisk,
|
||||
} from 'resources/cinder/snapshot';
|
||||
import FlavorSelectTable from '../../../components/FlavorSelectTable';
|
||||
|
||||
export class BaseStep extends Base {
|
||||
@ -126,11 +131,7 @@ export class BaseStep extends Base {
|
||||
}
|
||||
|
||||
get volumeTypes() {
|
||||
return (this.volumeTypeStore.list.data || []).map((it) => ({
|
||||
label: it.name,
|
||||
value: it.id,
|
||||
originData: toJS(it),
|
||||
}));
|
||||
return volumeTypes();
|
||||
}
|
||||
|
||||
get volumes() {
|
||||
@ -337,62 +338,53 @@ export class BaseStep extends Base {
|
||||
if (!id) {
|
||||
this.updateContext({
|
||||
instanceSnapshotDisk: null,
|
||||
instanceSnapshotDataVolumes: [],
|
||||
});
|
||||
this.setState({
|
||||
instanceSnapshotDisk: null,
|
||||
instanceSnapshotMinSize: 0,
|
||||
instanceSnapshotDataVolumes: [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
const detail = await this.instanceSnapshotStore.fetchDetail({ id });
|
||||
const detail =
|
||||
await this.instanceSnapshotStore.fetchInstanceSnapshotVolumeData({ id });
|
||||
const {
|
||||
snapshotDetail: { size: snapshotSize = 0, volume_type_id } = {},
|
||||
snapshotDetail: { size: snapshotSize = 0 } = {},
|
||||
block_device_mapping = '',
|
||||
volumeDetail,
|
||||
snapshotDetail,
|
||||
instanceSnapshotDataVolumes = [],
|
||||
} = detail;
|
||||
if (!volumeDetail) {
|
||||
this.updateContext({
|
||||
instanceSnapshotDisk: null,
|
||||
instanceSnapshotDataVolumes: [],
|
||||
});
|
||||
this.setState({
|
||||
instanceSnapshotDisk: null,
|
||||
instanceSnapshotMinSize: 0,
|
||||
instanceSnapshotDataVolumes: [],
|
||||
});
|
||||
}
|
||||
const minSize = Math.max(min_disk, size, snapshotSize);
|
||||
let bdm = {};
|
||||
try {
|
||||
bdm = JSON.parse(block_device_mapping);
|
||||
} catch (e) {}
|
||||
const { volume_type } = volumeDetail;
|
||||
const { delete_on_termination } = bdm[0] || {};
|
||||
const deleteType = delete_on_termination ? 1 : 0;
|
||||
const deleteTypeLabel = delete_on_termination
|
||||
? t('Deleted with the instance')
|
||||
: t('Not deleted with the instance');
|
||||
const volumeTypeId =
|
||||
volume_type_id ||
|
||||
(this.volumeTypes.find((it) => it.label === volume_type) || {}).value;
|
||||
const volumeTypeItem = this.volumeTypes.find(
|
||||
(it) => it.value === volumeTypeId
|
||||
);
|
||||
const instanceSnapshotDisk = volumeDetail
|
||||
? {
|
||||
type: volumeTypeId,
|
||||
typeOption: volumeTypeItem,
|
||||
size: snapshotSize,
|
||||
deleteType,
|
||||
deleteTypeLabel,
|
||||
}
|
||||
: null;
|
||||
|
||||
const bdmFormatData = JSON.parse(block_device_mapping) || [];
|
||||
const systemDiskBdm = bdmFormatData[0] || {};
|
||||
const instanceSnapshotDisk = getDiskInfo({
|
||||
volumeDetail,
|
||||
snapshotDetail,
|
||||
selfBdmData: systemDiskBdm,
|
||||
});
|
||||
this.updateFormValue('instanceSnapshotDisk', instanceSnapshotDisk);
|
||||
this.updateContext({
|
||||
instanceSnapshotDisk,
|
||||
instanceSnapshotDataVolumes,
|
||||
});
|
||||
this.setState({
|
||||
instanceSnapshotDisk,
|
||||
instanceSnapshotMinSize: minSize,
|
||||
instanceSnapshotDataVolumes,
|
||||
});
|
||||
};
|
||||
|
||||
@ -426,8 +418,14 @@ export class BaseStep extends Base {
|
||||
return instanceSnapshotDisk || oldDisk;
|
||||
};
|
||||
|
||||
renderSnapshotDisk = () => {
|
||||
const disk = this.getInstanceSnapshotDisk();
|
||||
getSnapshotDataDisks = () => {
|
||||
const { instanceSnapshotDataVolumes } = this.state;
|
||||
const { instanceSnapshotDataVolumes: oldSnapshotDataVolumes } =
|
||||
this.props.context;
|
||||
return instanceSnapshotDataVolumes || oldSnapshotDataVolumes || [];
|
||||
};
|
||||
|
||||
renderInstanceSnapshotDisk = (disk) => {
|
||||
if (disk === null) {
|
||||
return null;
|
||||
}
|
||||
@ -455,6 +453,28 @@ export class BaseStep extends Base {
|
||||
);
|
||||
};
|
||||
|
||||
renderSnapshotDisk = () => {
|
||||
const disk = this.getInstanceSnapshotDisk();
|
||||
return this.renderInstanceSnapshotDisk(disk);
|
||||
};
|
||||
|
||||
renderSnapshotDataDisk = () => {
|
||||
const dataDisks = this.getSnapshotDataDisks();
|
||||
return (
|
||||
<>
|
||||
{dataDisks?.map((i) => {
|
||||
const disk = getInstanceSnapshotDataDisk(i);
|
||||
const id = i?.id || i?.snapshot_id;
|
||||
return (
|
||||
<div style={{ marginBottom: 10 }} key={`data-disk-${id}`}>
|
||||
{this.renderInstanceSnapshotDisk(disk)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
get imageColumns() {
|
||||
return getImageColumns(this);
|
||||
}
|
||||
@ -533,6 +553,15 @@ export class BaseStep extends Base {
|
||||
);
|
||||
}
|
||||
|
||||
get hideInstanceSnapshotSystemDisk() {
|
||||
return this.showSystemDisk || this.sourceTypeIsVolume;
|
||||
}
|
||||
|
||||
get hideInstanceSnapshotDataDisk() {
|
||||
if (this.hideInstanceSnapshotSystemDisk) return true;
|
||||
return this.getSnapshotDataDisks().length === 0;
|
||||
}
|
||||
|
||||
getFlavorComponent() {
|
||||
return <FlavorSelectTable onChange={this.onFlavorChange} />;
|
||||
}
|
||||
@ -669,9 +698,15 @@ export class BaseStep extends Base {
|
||||
{
|
||||
name: 'instanceSnapshotDisk',
|
||||
label: t('System Disk'),
|
||||
hidden: this.showSystemDisk,
|
||||
hidden: this.hideInstanceSnapshotSystemDisk,
|
||||
component: this.renderSnapshotDisk(),
|
||||
},
|
||||
{
|
||||
name: 'instanceSnapshotDataDisk',
|
||||
label: t('Required Data Disk'),
|
||||
hidden: this.hideInstanceSnapshotDataDisk,
|
||||
component: this.renderSnapshotDataDisk(),
|
||||
},
|
||||
{
|
||||
name: 'dataDisk',
|
||||
label: t('Data Disk'),
|
||||
|
60
src/resources/cinder/snapshot.jsx
Normal file
60
src/resources/cinder/snapshot.jsx
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2022 99cloud
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import globalVolumeTypeStore from 'stores/cinder/volume-type';
|
||||
import { toJS } from 'mobx';
|
||||
|
||||
export const volumeTypes = () => {
|
||||
return (globalVolumeTypeStore.list.data || []).map((it) => ({
|
||||
label: it.name,
|
||||
value: it.id,
|
||||
originData: toJS(it),
|
||||
}));
|
||||
};
|
||||
|
||||
export const getDiskInfo = (detail) => {
|
||||
const {
|
||||
snapshotDetail: { size = 0 } = {},
|
||||
volumeDetail: { volume_type } = {},
|
||||
selfBdmData = {},
|
||||
} = detail || {};
|
||||
const { delete_on_termination } = selfBdmData;
|
||||
const deleteType = delete_on_termination ? 1 : 0;
|
||||
const deleteTypeLabel = delete_on_termination
|
||||
? t('Deleted with the instance')
|
||||
: t('Not deleted with the instance');
|
||||
const volumeTypeItem = volumeTypes().find((it) => it.label === volume_type);
|
||||
const diskInfo = {
|
||||
type: volumeTypeItem?.value,
|
||||
typeOption: volumeTypeItem,
|
||||
size,
|
||||
deleteType,
|
||||
deleteTypeLabel,
|
||||
};
|
||||
return diskInfo;
|
||||
};
|
||||
|
||||
export const getInstanceSnapshotDataDisk = (disk) => {
|
||||
const {
|
||||
volumeDetail,
|
||||
snapshotDetail,
|
||||
bdmFormatData: dataDiskBdm = {},
|
||||
} = disk || {};
|
||||
const instanceSnapshotDataDisk = getDiskInfo({
|
||||
volumeDetail,
|
||||
snapshotDetail,
|
||||
selfBdmData: dataDiskBdm,
|
||||
});
|
||||
return instanceSnapshotDataDisk;
|
||||
};
|
@ -14,6 +14,7 @@
|
||||
|
||||
import client from 'client';
|
||||
import { isSnapshot } from 'src/resources/glance/image';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import Base from '../base';
|
||||
|
||||
export class InstanceSnapshotStore extends Base {
|
||||
@ -152,6 +153,43 @@ export class InstanceSnapshotStore extends Base {
|
||||
item.instanceDetail = instanceResult.server || {};
|
||||
return item;
|
||||
}
|
||||
|
||||
async fetchInstanceSnapshotVolumeData({ id }) {
|
||||
const snapshotDetailInfo = await this.client.show(id);
|
||||
const instanceSnapshotDetail = await this.detailDidFetch(
|
||||
snapshotDetailInfo
|
||||
);
|
||||
const { block_device_mapping: bdm = '[]' } = instanceSnapshotDetail;
|
||||
const bdmFormatData = JSON.parse(bdm) || [];
|
||||
if (!bdmFormatData?.length) {
|
||||
return instanceSnapshotDetail;
|
||||
}
|
||||
const snapshotsOfDataDisk = bdmFormatData?.filter(
|
||||
(it) => it.boot_index !== 0
|
||||
);
|
||||
const snapshotsReqs = snapshotsOfDataDisk.map(async (i) => {
|
||||
const snapshot = cloneDeep(i);
|
||||
const { snapshot_id } = i;
|
||||
const snapshotResult = await client.cinder.snapshots.show(snapshot_id);
|
||||
const snapshotDetail = snapshotResult?.snapshot || {};
|
||||
snapshot.snapshotDetail = snapshotDetail;
|
||||
snapshot.bdmFormatData = i;
|
||||
return snapshot;
|
||||
});
|
||||
const snapshotsOfDataDiskRes = await Promise.all(snapshotsReqs);
|
||||
const volumesReqs = snapshotsOfDataDiskRes.map(async (i) => {
|
||||
const { volume_id } = i.snapshotDetail;
|
||||
const volumesResult = await client.cinder.volumes.show(volume_id);
|
||||
const volumeDetail = volumesResult?.volume || {};
|
||||
i.volumeDetail = volumeDetail;
|
||||
return i;
|
||||
});
|
||||
const instanceSnapshotDataVolumes = await Promise.all(volumesReqs);
|
||||
return {
|
||||
...instanceSnapshotDetail,
|
||||
instanceSnapshotDataVolumes,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const globalInstanceSnapshotStore = new InstanceSnapshotStore();
|
||||
|
Loading…
Reference in New Issue
Block a user