Skip to content

Commit

Permalink
Allow cleaner way to consume ISO with virt VM instances (#15390)
Browse files Browse the repository at this point in the history
  • Loading branch information
Qubad786 authored Jan 15, 2025
1 parent 93ff9fc commit 28b1247
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
6 changes: 5 additions & 1 deletion src/middlewared/middlewared/api/v25_04_0/virt_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ class VirtInstanceEntry(BaseModel):
@single_argument_args('virt_instance_create')
class VirtInstanceCreateArgs(BaseModel):
name: Annotated[NonEmptyString, StringConstraints(max_length=200)]
source_type: Literal[None, 'IMAGE'] = 'IMAGE'
source_type: Literal[None, 'IMAGE', 'ISO'] = 'IMAGE'
iso_volume: NonEmptyString | None = None
image: Annotated[NonEmptyString, StringConstraints(max_length=200)] | None = None
remote: REMOTE_CHOICES = 'LINUX_CONTAINERS'
instance_type: InstanceType = 'CONTAINER'
Expand All @@ -98,6 +99,9 @@ def validate_attrs(self):
if self.enable_vnc and self.vnc_port is None:
raise ValueError('VNC port must be set when VNC is enabled')

if self.source_type == 'ISO' and self.iso_volume is None:
raise ValueError('ISO volume must be set when source type is "ISO"')

if self.source_type == 'IMAGE' and self.image is None:
raise ValueError('Image must be set when source type is "IMAGE"')

Expand Down
26 changes: 24 additions & 2 deletions src/middlewared/middlewared/plugins/virt/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ async def query(self, filters, options):
@private
async def validate(self, new, schema_name, verrors, old=None):
# Do not validate image_choices because its an expansive operation, just fail on creation

instance_type = new.get('instance_type') or (old or {}).get('type')
if instance_type and not await self.middleware.call('virt.global.license_active', instance_type):
verrors.add(
Expand Down Expand Up @@ -169,6 +168,15 @@ async def validate(self, new, schema_name, verrors, old=None):
'enable_vnc': True,
'vnc_port': old['vnc_port'],
})
else:
# Creation case
if new['source_type'] == 'ISO' and not await self.middleware.call(
'virt.volume.query', [['content_type', '=', 'ISO'], ['id', '=', new['iso_volume']]]
):
verrors.add(
f'{schema_name}.iso_volume',
'Invalid ISO volume selected. Please select a valid ISO volume.'
)

if instance_type == 'VM' and new.get('enable_vnc'):
if not new.get('vnc_port'):
Expand Down Expand Up @@ -267,7 +275,21 @@ async def do_create(self, job, data):
await self.validate(data, 'virt_instance_create', verrors)

devices = {}
for i in (data['devices'] or []):
data_devices = data['devices'] or []
iso_volume = data.pop('iso_volume', None)
if data['source_type'] == 'ISO':
data['source_type'] = None
data_devices.append({
'name': iso_volume,
'dev_type': 'DISK',
'pool': 'default',
'source': iso_volume,
'destination': None,
'readonly': False,
'boot_priority': 1,
})

for i in data_devices:
await self.middleware.call(
'virt.instance.validate_device', i, 'virt_instance_create', verrors, data['instance_type'],
)
Expand Down
35 changes: 35 additions & 0 deletions tests/api2/test_virt_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,41 @@ def test_vm_iso_volume(vm, iso_volume):
assert iso_vol['used_by'] == [VM_NAME], iso_vol


def test_vm_creation_with_iso_volume(vm, iso_volume):
virt_instance_name = 'test-iso-vm'
call('virt.instance.create', {
'name': virt_instance_name,
'instance_type': 'VM',
'source_type': 'ISO',
'iso_volume': ISO_VOLUME_NAME,
}, job=True)

try:
vm_devices = call('virt.instance.device_list', virt_instance_name)
assert any(device['name'] == ISO_VOLUME_NAME for device in vm_devices), vm_devices

iso_vol = call('virt.volume.get_instance', ISO_VOLUME_NAME)
assert iso_vol['used_by'] == [virt_instance_name], iso_vol
finally:
call('virt.instance.delete', virt_instance_name, job=True)


@pytest.mark.parametrize('iso_volume,error_msg', [
(None, 'Value error, ISO volume must be set when source type is "ISO"'),
('test_iso123', 'Invalid ISO volume selected. Please select a valid ISO volume.'),
])
def test_iso_param_validation_on_vm_create(virt_pool, iso_volume, error_msg):
with pytest.raises(ValidationErrors) as ve:
call('virt.instance.create', {
'name': 'test-iso-vm2',
'instance_type': 'VM',
'source_type': 'ISO',
'iso_volume': iso_volume
}, job=True)

assert ve.value.errors[0].errmsg == error_msg


@pytest.mark.parametrize('enable_vnc,vnc_port,error_msg', [
(True, None, 'Value error, VNC port must be set when VNC is enabled'),
(True, 6901, 'VNC port is already in use by another virt instance'),
Expand Down

0 comments on commit 28b1247

Please sign in to comment.