feat: support create non-bfv instance

support create non-bfv instance

Closes-Bug: #2003057
Change-Id: If494648f4d42c6da54661400283968c7220bf2a4
This commit is contained in:
Jingwei.Zhang 2023-09-28 17:18:39 +08:00
parent 12bc328c24
commit 6a186ee521
4 changed files with 145 additions and 27 deletions

View File

@ -0,0 +1,10 @@
---
fixes:
- |
`Feature #2003057 <https://bugs.launchpad.net/skyline-apiserver/+bug/2003057>`_:
Support create No-BFV instance:
* Support no-boot-from-volume selector when create instance by image or instance snapshot.
* When create a no-boot-from-volume instance, you can not add data disk in the step forms, but you can attach volumes when the instance has been created.

View File

@ -82,6 +82,9 @@ export class BaseStep extends Base {
project: this.currentProjectName,
dataDisk: [],
};
if (source.value === 'image') {
values.bootFromVolume = true;
}
return values;
}
@ -272,7 +275,14 @@ export class BaseStep extends Base {
};
get nameForStateUpdate() {
return ['source', 'image', 'instanceSnapshot', 'bootableVolume', 'flavor'];
return [
'source',
'image',
'instanceSnapshot',
'bootableVolume',
'flavor',
'bootFromVolume',
];
}
getSystemDiskMinSize() {
@ -333,6 +343,17 @@ export class BaseStep extends Base {
});
};
onChangeBootFromVolume = (value) => {
const newData = {
bootFromVolume: value,
};
if (!value) {
newData.dataDisk = [];
this.updateFormValue('dataDisk', []);
}
this.updateContext(newData);
};
onInstanceSnapshotChange = async (value) => {
const { min_disk, size, id } = value.selectedRows[0] || {};
if (!id) {
@ -357,14 +378,17 @@ export class BaseStep extends Base {
instanceSnapshotDataVolumes = [],
} = detail;
if (!volumeDetail) {
this.updateFormValue('bootFromVolume', true);
this.updateContext({
instanceSnapshotDisk: null,
instanceSnapshotDataVolumes: [],
bootFromVolume: true,
});
this.setState({
instanceSnapshotDisk: null,
instanceSnapshotMinSize: 0,
instanceSnapshotDataVolumes: [],
bootFromVolume: true,
});
}
const minSize = Math.max(min_disk, size, snapshotSize);
@ -544,6 +568,36 @@ export class BaseStep extends Base {
];
}
get supportNoBootFromVolume() {
return true;
}
get showBootFromVolumeFormItem() {
if (!this.supportNoBootFromVolume) {
return false;
}
if (!this.enableCinder) {
return false;
}
if (this.sourceTypeIsImage) {
return true;
}
return this.showSystemDisk;
}
get bootFromVolumeOptions() {
return [
{
value: true,
label: t('Yes - Create a new system disk'),
},
{
value: false,
label: t('No - Do not create a new system disk'),
},
];
}
get showSystemDisk() {
const snapshotDisk = this.getInstanceSnapshotDisk();
return (
@ -553,6 +607,18 @@ export class BaseStep extends Base {
);
}
get showSystemDiskByBootFromVolume() {
if (!this.showSystemDisk) {
return false;
}
if (!this.supportNoBootFromVolume) {
return true;
}
// support non-bfv and bootFromVolume = true
const { bootFromVolume = true } = this.state;
return !!bootFromVolume;
}
get hideInstanceSnapshotSystemDisk() {
return this.showSystemDisk || this.sourceTypeIsVolume;
}
@ -562,6 +628,17 @@ export class BaseStep extends Base {
return this.getSnapshotDataDisks().length === 0;
}
get hideDataDisk() {
if (!this.supportNoBootFromVolume) {
return false;
}
if (this.sourceTypeIsVolume) {
return false;
}
const { bootFromVolume = true } = this.state;
return !bootFromVolume;
}
getFlavorComponent() {
return <FlavorSelectTable onChange={this.onFlavorChange} />;
}
@ -683,13 +760,30 @@ export class BaseStep extends Base {
{
type: 'divider',
},
{
name: 'bootFromVolume',
label: t('Boot From Volume'),
type: 'radio',
required: this.showBootFromVolumeFormItem,
hidden: !this.showBootFromVolumeFormItem,
onChange: this.onChangeBootFromVolume,
wrapperCol: {
xs: {
span: 16,
},
sm: {
span: 14,
},
},
options: this.bootFromVolumeOptions,
},
{
name: 'systemDisk',
label: t('System Disk'),
type: 'instance-volume',
options: this.volumeTypes,
required: this.showSystemDisk,
hidden: !this.showSystemDisk,
required: this.showSystemDiskByBootFromVolume,
hidden: !this.showSystemDiskByBootFromVolume,
validator: this.checkSystemDisk,
minSize: this.getSystemDiskMinSize(),
extra: t('Disk size is limited by the min disk of flavor, image, etc.'),
@ -713,6 +807,7 @@ export class BaseStep extends Base {
type: 'add-select',
options: this.volumeTypes,
defaultItemValue: this.defaultVolumeType,
hidden: this.hideDataDisk,
itemComponent: InstanceVolume,
minCount: 0,
addTextTips: t('Data Disks'),

View File

@ -36,7 +36,10 @@ export class ConfirmStep extends Base {
allowed = () => Promise.resolve();
getDisk(diskInfo) {
getDisk(diskInfo, bootFromVolume) {
if (!bootFromVolume) {
return null;
}
const { size, typeOption, deleteTypeLabel } = diskInfo || {};
return `${typeOption.label} ${size}GiB ${deleteTypeLabel}`;
}
@ -54,14 +57,15 @@ export class ConfirmStep extends Base {
systemDisk,
source: { value } = {},
instanceSnapshotDisk,
bootFromVolume = true,
} = context;
if (value === 'bootableVolume') {
return this.getBootableVolumeDisk();
}
if (value === 'instanceSnapshot' && instanceSnapshotDisk !== null) {
return this.getDisk(instanceSnapshotDisk);
return this.getDisk(instanceSnapshotDisk, bootFromVolume);
}
return this.getDisk(systemDisk);
return this.getDisk(systemDisk, bootFromVolume);
}
getDataDisk() {
@ -79,7 +83,7 @@ export class ConfirmStep extends Base {
) {
allDataDisks = getAllDataDisks({ dataDisk, instanceSnapshotDataVolumes });
}
return allDataDisks.map((it) => this.getDisk(it.value));
return allDataDisks.map((it) => this.getDisk(it.value, true));
}
getFlavor() {

View File

@ -301,6 +301,7 @@ export class StepCreate extends StepAction {
source: { value: sourceValue } = {},
instanceSnapshotDisk = {},
instanceSnapshotDataVolumes = [],
bootFromVolume = true,
} = data;
const newCountMap = {};
const newSizeMap = {};
@ -309,7 +310,7 @@ export class StepCreate extends StepAction {
const isSnapshotType = sourceValue === 'instanceSnapshot';
if (isSnapshotType && instanceSnapshotDisk) {
const { size, typeOption: { label } = {} } = instanceSnapshotDisk;
if (label) {
if (label && bootFromVolume) {
newCountMap[label] = !newCountMap[label] ? 1 : newCountMap[label] + 1;
newSizeMap[label] = !newSizeMap[label]
? size
@ -317,7 +318,7 @@ export class StepCreate extends StepAction {
totalNewCount += 1 * count;
totalNewSize += size * count;
}
} else if (systemDisk.type) {
} else if (systemDisk.type && bootFromVolume) {
const { size } = systemDisk;
const { label } = systemDisk.typeOption || {};
newCountMap[label] = !newCountMap[label] ? 1 : newCountMap[label] + 1;
@ -577,6 +578,7 @@ export class StepCreate extends StepAction {
instanceSnapshotDisk,
source,
systemDisk,
bootFromVolume = true,
} = values;
const { value: sourceValue } = source;
const imageRef =
@ -592,21 +594,23 @@ export class StepCreate extends StepAction {
}
let rootVolume = {};
if (sourceValue !== 'bootableVolume') {
const { deleteType, type, size } = systemDisk || {};
rootVolume = {
boot_index: 0,
uuid: imageRef,
source_type: 'image',
volume_size: size,
destination_type: 'volume',
volume_type: type,
delete_on_termination: deleteType === 1,
};
if (sourceValue === 'instanceSnapshot') {
if (instanceSnapshotDisk) {
delete rootVolume.volume_size;
delete rootVolume.volume_type;
delete rootVolume.delete_on_termination;
if (bootFromVolume) {
const { deleteType, type, size } = systemDisk || {};
rootVolume = {
boot_index: 0,
uuid: imageRef,
source_type: 'image',
volume_size: size,
destination_type: 'volume',
volume_type: type,
delete_on_termination: deleteType === 1,
};
if (sourceValue === 'instanceSnapshot') {
if (instanceSnapshotDisk) {
delete rootVolume.volume_size;
delete rootVolume.volume_type;
delete rootVolume.delete_on_termination;
}
}
}
} else {
@ -636,15 +640,19 @@ export class StepCreate extends StepAction {
if (
sourceValue === 'image' &&
image.selectedRows[0].disk_format === 'iso' &&
dataVolumes[0]
dataVolumes[0] &&
bootFromVolume
) {
dataVolumes[0].boot_index = 0;
dataVolumes[0].device_type = 'disk';
rootVolume.boot_index = 1;
rootVolume.device_type = 'cdrom';
}
const volumes = isEmpty(rootVolume)
? [...dataVolumes]
: [rootVolume, ...dataVolumes];
return {
volumes: [rootVolume, ...dataVolumes],
volumes,
imageRef,
};
}
@ -695,6 +703,7 @@ export class StepCreate extends StepAction {
serverGroup,
name,
count = 1,
bootFromVolume = true,
} = values;
if (hasIp && count > 1) {
this.ipBatchError = true;
@ -714,7 +723,7 @@ export class StepCreate extends StepAction {
if (this.enableCinder) {
server.block_device_mapping_v2 = volumes;
}
if (imageRef && !volumes) {
if (imageRef && (!volumes || !bootFromVolume)) {
server.imageRef = imageRef;
}
if (loginType.value === 'keypair') {