Merge "feat: support instance snapshot create instance"
This commit is contained in:
commit
6c746303c6
@ -15,9 +15,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import { toJS } from 'mobx';
|
import { toJS } from 'mobx';
|
||||||
|
import { Row, Col } from 'antd';
|
||||||
import { volumeStatus, canCreateInstance } from 'resources/cinder/volume';
|
import { volumeStatus, canCreateInstance } from 'resources/cinder/volume';
|
||||||
import globalServerStore from 'stores/nova/instance';
|
import globalServerStore from 'stores/nova/instance';
|
||||||
import globalImageStore from 'stores/glance/image';
|
import globalImageStore from 'stores/glance/image';
|
||||||
|
import globalInstanceSnapshotStore from 'stores/glance/instance-snapshot';
|
||||||
import globalVolumeTypeStore from 'stores/cinder/volume-type';
|
import globalVolumeTypeStore from 'stores/cinder/volume-type';
|
||||||
import globalAvailabilityZoneStore from 'stores/nova/zone';
|
import globalAvailabilityZoneStore from 'stores/nova/zone';
|
||||||
import { VolumeStore } from 'stores/cinder/volume';
|
import { VolumeStore } from 'stores/cinder/volume';
|
||||||
@ -26,6 +28,8 @@ import {
|
|||||||
getImageSystemTabs,
|
getImageSystemTabs,
|
||||||
getImageOS,
|
getImageOS,
|
||||||
getImageColumns,
|
getImageColumns,
|
||||||
|
imageFormats,
|
||||||
|
imageStatus,
|
||||||
} from 'resources/glance/image';
|
} from 'resources/glance/image';
|
||||||
import Base from 'components/Form';
|
import Base from 'components/Form';
|
||||||
import InstanceVolume from 'components/FormItem/InstanceVolume';
|
import InstanceVolume from 'components/FormItem/InstanceVolume';
|
||||||
@ -38,10 +42,13 @@ export class BaseStep extends Base {
|
|||||||
this.imageStore = globalImageStore;
|
this.imageStore = globalImageStore;
|
||||||
this.volumeStore = new VolumeStore();
|
this.volumeStore = new VolumeStore();
|
||||||
this.volumeTypeStore = globalVolumeTypeStore;
|
this.volumeTypeStore = globalVolumeTypeStore;
|
||||||
|
this.instanceSnapshotStore = globalInstanceSnapshotStore;
|
||||||
this.getAvailZones();
|
this.getAvailZones();
|
||||||
this.getImages();
|
this.getImages();
|
||||||
this.getVolumeTypes();
|
this.getVolumeTypes();
|
||||||
this.getVolumes();
|
this.getVolumes();
|
||||||
|
this.getInstanceSnapshots();
|
||||||
|
this.initSourceChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
@ -57,10 +64,12 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get defaultValue() {
|
get defaultValue() {
|
||||||
const { volume } = this.locationParams;
|
const { volume, snapshot } = this.locationParams;
|
||||||
let source = this.imageSourceType;
|
let source = this.imageSourceType;
|
||||||
if (volume) {
|
if (volume) {
|
||||||
source = this.volumeSourceType;
|
source = this.volumeSourceType;
|
||||||
|
} else if (snapshot) {
|
||||||
|
source = this.snapshotSourceType;
|
||||||
}
|
}
|
||||||
const values = {
|
const values = {
|
||||||
systemDisk: this.defaultVolumeType,
|
systemDisk: this.defaultVolumeType,
|
||||||
@ -101,6 +110,17 @@ export class BaseStep extends Base {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get snapshots() {
|
||||||
|
const { snapshot } = this.locationParams;
|
||||||
|
if (!snapshot) {
|
||||||
|
const {
|
||||||
|
list: { data },
|
||||||
|
} = this.instanceSnapshotStore;
|
||||||
|
return data || [];
|
||||||
|
}
|
||||||
|
return [toJS(this.instanceSnapshotStore.detail)];
|
||||||
|
}
|
||||||
|
|
||||||
get enableCinder() {
|
get enableCinder() {
|
||||||
return this.props.rootStore.checkEndpoint('cinder');
|
return this.props.rootStore.checkEndpoint('cinder');
|
||||||
}
|
}
|
||||||
@ -137,13 +157,20 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get sourceTypes() {
|
get sourceTypes() {
|
||||||
const { image, volume } = this.locationParams;
|
const { image, snapshot, volume } = this.locationParams;
|
||||||
const types = [{ label: t('Image'), value: 'image', disabled: volume }];
|
const types = [
|
||||||
|
{ label: t('Image'), value: 'image', disabled: volume || snapshot },
|
||||||
|
{
|
||||||
|
label: t('Instance Snapshot'),
|
||||||
|
value: 'instanceSnapshot',
|
||||||
|
disabled: image || volume,
|
||||||
|
},
|
||||||
|
];
|
||||||
if (this.enableCinder) {
|
if (this.enableCinder) {
|
||||||
types.push({
|
types.push({
|
||||||
label: t('Bootable Volume'),
|
label: t('Bootable Volume'),
|
||||||
value: 'bootableVolume',
|
value: 'bootableVolume',
|
||||||
disabled: image,
|
disabled: image || snapshot,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return types;
|
return types;
|
||||||
@ -153,6 +180,10 @@ export class BaseStep extends Base {
|
|||||||
return this.sourceTypes.find((it) => it.value === 'image');
|
return this.sourceTypes.find((it) => it.value === 'image');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get snapshotSourceType() {
|
||||||
|
return this.sourceTypes.find((it) => it.value === 'instanceSnapshot');
|
||||||
|
}
|
||||||
|
|
||||||
get volumeSourceType() {
|
get volumeSourceType() {
|
||||||
return this.enableCinder
|
return this.enableCinder
|
||||||
? this.sourceTypes.find((it) => it.value === 'bootableVolume')
|
? this.sourceTypes.find((it) => it.value === 'bootableVolume')
|
||||||
@ -169,8 +200,8 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getImages() {
|
async getImages() {
|
||||||
const { volume, image } = this.locationParams;
|
const { volume, image, snapshot } = this.locationParams;
|
||||||
if (volume) {
|
if (volume || snapshot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (image) {
|
if (image) {
|
||||||
@ -193,8 +224,8 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getVolumes() {
|
async getVolumes() {
|
||||||
const { image, volume } = this.locationParams;
|
const { image, snapshot, volume } = this.locationParams;
|
||||||
if (image) {
|
if (image || snapshot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.enableCinder) {
|
if (!this.enableCinder) {
|
||||||
@ -221,6 +252,21 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getInstanceSnapshots() {
|
||||||
|
const { snapshot } = this.locationParams;
|
||||||
|
if (!snapshot) {
|
||||||
|
this.instanceSnapshotStore.fetchList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.instanceSnapshotStore.fetchDetail({ id: snapshot });
|
||||||
|
if (snapshot) {
|
||||||
|
this.updateFormValue('instanceSnapshot', {
|
||||||
|
selectedRowKeys: [snapshot],
|
||||||
|
selectedRows: this.snapshots.filter((it) => it.id === snapshot),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onImageTabChange = (value) => {
|
onImageTabChange = (value) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
imageTab: value,
|
imageTab: value,
|
||||||
@ -240,7 +286,7 @@ export class BaseStep extends Base {
|
|||||||
};
|
};
|
||||||
|
|
||||||
get nameForStateUpdate() {
|
get nameForStateUpdate() {
|
||||||
return ['source', 'image', 'bootableVolume', 'flavor'];
|
return ['source', 'image', 'instanceSnapshot', 'bootableVolume', 'flavor'];
|
||||||
}
|
}
|
||||||
|
|
||||||
getSystemDiskMinSize() {
|
getSystemDiskMinSize() {
|
||||||
@ -250,8 +296,13 @@ export class BaseStep extends Base {
|
|||||||
const { min_disk = 0, size = 0 } = this.state.image || {};
|
const { min_disk = 0, size = 0 } = this.state.image || {};
|
||||||
const sizeGiB = Math.ceil(size / 1024 / 1024 / 1024);
|
const sizeGiB = Math.ceil(size / 1024 / 1024 / 1024);
|
||||||
imageSize = Math.max(min_disk, sizeGiB, 1);
|
imageSize = Math.max(min_disk, sizeGiB, 1);
|
||||||
|
return Math.max(flavorSize, imageSize, 1);
|
||||||
}
|
}
|
||||||
return Math.max(flavorSize, imageSize, 1);
|
if (this.sourceTypeIsSnapshot) {
|
||||||
|
const { instanceSnapshotMinSize = 0 } = this.state;
|
||||||
|
return Math.max(flavorSize, instanceSnapshotMinSize, 1);
|
||||||
|
}
|
||||||
|
return Math.max(flavorSize, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
get sourceTypeIsImage() {
|
get sourceTypeIsImage() {
|
||||||
@ -259,6 +310,11 @@ export class BaseStep extends Base {
|
|||||||
return source === this.imageSourceType.value;
|
return source === this.imageSourceType.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get sourceTypeIsSnapshot() {
|
||||||
|
const { source } = this.state;
|
||||||
|
return source === this.snapshotSourceType.value;
|
||||||
|
}
|
||||||
|
|
||||||
get sourceTypeIsVolume() {
|
get sourceTypeIsVolume() {
|
||||||
const { source } = this.state;
|
const { source } = this.state;
|
||||||
return source === this.volumeSourceType.value;
|
return source === this.volumeSourceType.value;
|
||||||
@ -274,12 +330,87 @@ export class BaseStep extends Base {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initSourceChange() {
|
||||||
|
const { snapshot, volume } = this.locationParams;
|
||||||
|
if (snapshot) {
|
||||||
|
this.onSourceChange(this.snapshotSourceType);
|
||||||
|
} else if (volume) {
|
||||||
|
this.onSourceChange(this.volumeSourceType);
|
||||||
|
} else {
|
||||||
|
this.onSourceChange(this.imageSourceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onFlavorChange = (value) => {
|
onFlavorChange = (value) => {
|
||||||
this.updateContext({
|
this.updateContext({
|
||||||
flavor: value,
|
flavor: value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onInstanceSnapshotChange = async (value) => {
|
||||||
|
const { min_disk, size, id } = value.selectedRows[0] || {};
|
||||||
|
if (!id) {
|
||||||
|
this.updateContext({
|
||||||
|
instanceSnapshotDisk: null,
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
instanceSnapshotDisk: null,
|
||||||
|
instanceSnapshotMinSize: 0,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const detail = await this.instanceSnapshotStore.fetchDetail({ id });
|
||||||
|
const {
|
||||||
|
snapshotDetail: { size: snapshotSize = 0, volume_type_id } = {},
|
||||||
|
block_device_mapping = '',
|
||||||
|
volumeDetail,
|
||||||
|
} = detail;
|
||||||
|
if (!volumeDetail) {
|
||||||
|
this.updateContext({
|
||||||
|
instanceSnapshotDisk: null,
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
instanceSnapshotDisk: null,
|
||||||
|
instanceSnapshotMinSize: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
this.updateFormValue('instanceSnapshotDisk', instanceSnapshotDisk);
|
||||||
|
this.updateContext({
|
||||||
|
instanceSnapshotDisk,
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
instanceSnapshotDisk,
|
||||||
|
instanceSnapshotMinSize: minSize,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onBootableVolumeChange = (value) => {
|
onBootableVolumeChange = (value) => {
|
||||||
this.updateContext({
|
this.updateContext({
|
||||||
bootableVolume: value,
|
bootableVolume: value,
|
||||||
@ -304,10 +435,80 @@ export class BaseStep extends Base {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getInstanceSnapshotDisk = () => {
|
||||||
|
const { instanceSnapshotDisk } = this.state;
|
||||||
|
const { instanceSnapshotDisk: oldDisk } = this.props.context;
|
||||||
|
return instanceSnapshotDisk || oldDisk;
|
||||||
|
};
|
||||||
|
|
||||||
|
renderSnapshotDisk = () => {
|
||||||
|
const disk = this.getInstanceSnapshotDisk();
|
||||||
|
if (disk === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { deleteTypeLabel, typeOption = {}, size } = disk || {};
|
||||||
|
if (!size) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const style = {
|
||||||
|
marginRight: 10,
|
||||||
|
maxWidth: '20%',
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Row gutter={24}>
|
||||||
|
<Col span={8}>
|
||||||
|
<span style={style}>{t('Type')}</span>
|
||||||
|
{typeOption.label}
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<span style={style}>{t('Size')}</span>
|
||||||
|
{size}
|
||||||
|
<span style={style}>GiB</span>
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>{deleteTypeLabel}</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
get imageColumns() {
|
get imageColumns() {
|
||||||
return getImageColumns(this);
|
return getImageColumns(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get instanceSnapshotColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: t('Name'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Disk Format'),
|
||||||
|
dataIndex: 'disk_format',
|
||||||
|
render: (value) => imageFormats[value] || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Min System Disk'),
|
||||||
|
dataIndex: 'min_disk',
|
||||||
|
render: (text) => `${text}GiB`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Min Memory'),
|
||||||
|
dataIndex: 'min_ram',
|
||||||
|
render: (text) => `${text / 1024}GiB`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Status'),
|
||||||
|
dataIndex: 'status',
|
||||||
|
render: (value) => imageStatus[value] || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Created At'),
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
isHideable: true,
|
||||||
|
valueRender: 'sinceTime',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
get volumeColumns() {
|
get volumeColumns() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -339,7 +540,12 @@ export class BaseStep extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get showSystemDisk() {
|
get showSystemDisk() {
|
||||||
return this.enableCinder && this.sourceTypeIsImage;
|
const snapshotDisk = this.getInstanceSnapshotDisk();
|
||||||
|
return (
|
||||||
|
this.enableCinder &&
|
||||||
|
(this.sourceTypeIsImage ||
|
||||||
|
(this.sourceTypeIsSnapshot && snapshotDisk === null))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFlavorComponent() {
|
getFlavorComponent() {
|
||||||
@ -424,6 +630,24 @@ export class BaseStep extends Base {
|
|||||||
selectedLabel: t('Image'),
|
selectedLabel: t('Image'),
|
||||||
onTabChange: this.onImageTabChange,
|
onTabChange: this.onImageTabChange,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'instanceSnapshot',
|
||||||
|
label: t('Instance Snapshot'),
|
||||||
|
type: 'select-table',
|
||||||
|
data: this.snapshots,
|
||||||
|
required: this.sourceTypeIsSnapshot,
|
||||||
|
isMulti: false,
|
||||||
|
hidden: !this.sourceTypeIsSnapshot,
|
||||||
|
display: this.sourceTypeIsSnapshot,
|
||||||
|
onChange: this.onInstanceSnapshotChange,
|
||||||
|
filterParams: [
|
||||||
|
{
|
||||||
|
label: t('Name'),
|
||||||
|
name: 'name',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columns: this.instanceSnapshotColumns,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'bootableVolume',
|
name: 'bootableVolume',
|
||||||
label: t('Bootable Volume'),
|
label: t('Bootable Volume'),
|
||||||
@ -457,6 +681,12 @@ export class BaseStep extends Base {
|
|||||||
extra: t('Disk size is limited by the min disk of flavor, image, etc.'),
|
extra: t('Disk size is limited by the min disk of flavor, image, etc.'),
|
||||||
onChange: this.onSystemDiskChange,
|
onChange: this.onSystemDiskChange,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'instanceSnapshotDisk',
|
||||||
|
label: t('System Disk'),
|
||||||
|
hidden: this.showSystemDisk,
|
||||||
|
component: this.renderSnapshotDisk(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'dataDisk',
|
name: 'dataDisk',
|
||||||
label: t('Data Disk'),
|
label: t('Data Disk'),
|
||||||
|
@ -49,10 +49,18 @@ export class ConfirmStep extends Base {
|
|||||||
getSystemDisk() {
|
getSystemDisk() {
|
||||||
if (!this.enableCinder) return null;
|
if (!this.enableCinder) return null;
|
||||||
const { context } = this.props;
|
const { context } = this.props;
|
||||||
const { systemDisk, source } = context;
|
const {
|
||||||
return source.value === 'bootableVolume'
|
systemDisk,
|
||||||
? this.getBootableVolumeDisk()
|
source: { value } = {},
|
||||||
: this.getDisk(systemDisk);
|
instanceSnapshotDisk,
|
||||||
|
} = context;
|
||||||
|
if (value === 'bootableVolume') {
|
||||||
|
return this.getBootableVolumeDisk();
|
||||||
|
}
|
||||||
|
if (value === 'instanceSnapshot' && instanceSnapshotDisk !== null) {
|
||||||
|
return this.getDisk(instanceSnapshotDisk);
|
||||||
|
}
|
||||||
|
return this.getDisk(systemDisk);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataDisk() {
|
getDataDisk() {
|
||||||
|
@ -275,12 +275,28 @@ export class StepCreate extends StepAction {
|
|||||||
|
|
||||||
getVolumeInputMap() {
|
getVolumeInputMap() {
|
||||||
const { data } = this.state;
|
const { data } = this.state;
|
||||||
const { systemDisk = {}, dataDisk = [], count = 1 } = data;
|
const {
|
||||||
|
systemDisk = {},
|
||||||
|
dataDisk = [],
|
||||||
|
count = 1,
|
||||||
|
source: { value: sourceValue } = {},
|
||||||
|
instanceSnapshotDisk = {},
|
||||||
|
} = data;
|
||||||
const newCountMap = {};
|
const newCountMap = {};
|
||||||
const newSizeMap = {};
|
const newSizeMap = {};
|
||||||
let totalNewCount = 0;
|
let totalNewCount = 0;
|
||||||
let totalNewSize = 0;
|
let totalNewSize = 0;
|
||||||
if (systemDisk.type) {
|
if (sourceValue === 'instanceSnapshot' && instanceSnapshotDisk) {
|
||||||
|
const { size, typeOption: { label } = {} } = instanceSnapshotDisk;
|
||||||
|
if (label) {
|
||||||
|
newCountMap[label] = !newCountMap[label] ? 1 : newCountMap[label] + 1;
|
||||||
|
newSizeMap[label] = !newSizeMap[label]
|
||||||
|
? size
|
||||||
|
: newSizeMap[label] + size;
|
||||||
|
totalNewCount += 1 * count;
|
||||||
|
totalNewSize += size * count;
|
||||||
|
}
|
||||||
|
} else if (systemDisk.type) {
|
||||||
const { size } = systemDisk;
|
const { size } = systemDisk;
|
||||||
const { label } = systemDisk.typeOption || {};
|
const { label } = systemDisk.typeOption || {};
|
||||||
newCountMap[label] = !newCountMap[label] ? 1 : newCountMap[label] + 1;
|
newCountMap[label] = !newCountMap[label] ? 1 : newCountMap[label] + 1;
|
||||||
@ -460,6 +476,7 @@ export class StepCreate extends StepAction {
|
|||||||
dataDisk,
|
dataDisk,
|
||||||
image,
|
image,
|
||||||
instanceSnapshot,
|
instanceSnapshot,
|
||||||
|
instanceSnapshotDisk,
|
||||||
source,
|
source,
|
||||||
systemDisk,
|
systemDisk,
|
||||||
} = values;
|
} = values;
|
||||||
@ -477,7 +494,7 @@ export class StepCreate extends StepAction {
|
|||||||
}
|
}
|
||||||
let rootVolume = {};
|
let rootVolume = {};
|
||||||
if (sourceValue !== 'bootableVolume') {
|
if (sourceValue !== 'bootableVolume') {
|
||||||
const { deleteType, type, size } = systemDisk;
|
const { deleteType, type, size } = systemDisk || {};
|
||||||
rootVolume = {
|
rootVolume = {
|
||||||
boot_index: 0,
|
boot_index: 0,
|
||||||
uuid: imageRef,
|
uuid: imageRef,
|
||||||
@ -487,6 +504,13 @@ export class StepCreate extends StepAction {
|
|||||||
volume_type: type,
|
volume_type: type,
|
||||||
delete_on_termination: deleteType === 1,
|
delete_on_termination: deleteType === 1,
|
||||||
};
|
};
|
||||||
|
if (sourceValue === 'instanceSnapshot') {
|
||||||
|
if (instanceSnapshotDisk) {
|
||||||
|
delete rootVolume.volume_size;
|
||||||
|
delete rootVolume.volume_type;
|
||||||
|
delete rootVolume.delete_on_termination;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rootVolume = {
|
rootVolume = {
|
||||||
boot_index: 0,
|
boot_index: 0,
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
// 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 { inject, observer } from 'mobx-react';
|
||||||
|
import CreateInstance from 'pages/compute/containers/Instance/actions/StepCreate';
|
||||||
|
|
||||||
|
export class StepCreate extends CreateInstance {
|
||||||
|
static id = 'instance-create';
|
||||||
|
|
||||||
|
static title = t('Create Instance');
|
||||||
|
|
||||||
|
static path(item) {
|
||||||
|
return `/compute/instance/create?snapshot=${item.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static policy = 'os_compute_api:servers:create';
|
||||||
|
|
||||||
|
static allowed(item) {
|
||||||
|
return Promise.resolve(item.status === 'active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default inject('rootStore')(observer(StepCreate));
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import CreateVolume from './CreateVolume';
|
import CreateVolume from './CreateVolume';
|
||||||
|
import CreateInstance from './CreateInstance';
|
||||||
import Edit from './Edit';
|
import Edit from './Edit';
|
||||||
import Delete from './Delete';
|
import Delete from './Delete';
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ const actionConfigs = {
|
|||||||
rowActions: {
|
rowActions: {
|
||||||
firstAction: Edit,
|
firstAction: Edit,
|
||||||
moreActions: [
|
moreActions: [
|
||||||
|
{
|
||||||
|
action: CreateInstance,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
action: CreateVolume,
|
action: CreateVolume,
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user