This commit is contained in:
2026-09-18 12:19:28 +03:00
parent b2cb33e9a8
commit 1c0e5cfdb3
27 changed files with 1045 additions and 753 deletions

View File

@@ -456,9 +456,9 @@ class decort_vm(DecortController):
image_id=self.amodule.params['image_id'],
account_id=self.acc_id)
if validated_bdisk_size <= image_facts['size']:
if validated_bdisk_size <= image_facts['size_gb']:
# adjust disk size to the minimum allowed by OS image, which will be used to spin off this Compute
validated_bdisk_size = image_facts['size']
validated_bdisk_size = image_facts['size_gb']
# NOTE: due to a libvirt "feature", that impacts management of a VM created without any network interfaces,
# we create KVM VM in HALTED state.
@@ -495,6 +495,10 @@ class decort_vm(DecortController):
if numa_affinity is None:
numa_affinity = 'none'
clock_sync_mode = self.aparams['clock_sync_mode']
if clock_sync_mode is None:
clock_sync_mode = 'default'
chipset = self.amodule.params['chipset']
if chipset is None:
chipset = 'Q35'
@@ -552,6 +556,8 @@ class decort_vm(DecortController):
zone_id=self.aparams['zone_id'],
storage_policy_id=self.aparams['storage_policy_id'],
os_version=self.aparams['os_version'],
cpu_alignment_profile_name=self.aparams['cpu_alignment_profile_name'],
clock_sync_mode=clock_sync_mode,
)
self.comp_should_exist = True
@@ -704,9 +710,9 @@ class decort_vm(DecortController):
vm_disk=disk,
)
):
self.compute_boot_disk(
comp_id=self.comp_info['id'],
boot_disk=aparam_disk_id,
self.sdk_checkmode(self.api.cloudapi.compute.boot_disk_set)(
vm_id=self.comp_info['id'],
disk_id=aparam_disk_id,
)
break
@@ -744,7 +750,7 @@ class decort_vm(DecortController):
_, image_facts = self.image_find(
image_id=self.aparams['image_id'],
)
disk_size = image_facts['size']
disk_size = image_facts['size_gb']
os_version = None
if (
@@ -782,8 +788,8 @@ class decort_vm(DecortController):
compute_custom_fields = self.comp_info['custom_fields']
if aparam_custom_fields['disable']:
if compute_custom_fields is not None:
self.compute_disable_custom_fields(
compute_id=self.comp_info['id'],
self.sdk_checkmode(self.api.ca.compute.delete_custom_fields)(
vm_id=self.comp_info['id'],
)
else:
if compute_custom_fields != aparam_custom_fields['fields']:
@@ -794,8 +800,8 @@ class decort_vm(DecortController):
aparam_zone_id = self.aparams['zone_id']
if aparam_zone_id is not None and aparam_zone_id != self.comp_info['zoneId']:
self.compute_migrate_to_zone(
compute_id=self.comp_id,
self.sdk_checkmode(self.api.cloudapi.compute.migrate_to_zone)(
vm_id=self.comp_id,
zone_id=aparam_zone_id,
)
@@ -806,15 +812,21 @@ class decort_vm(DecortController):
aparam_guest_agent['enabled']
and not self.comp_info['qemu_guest']['enabled']
):
self.compute_guest_agent_enable(vm_id=self.comp_id)
self.sdk_checkmode(
self.api.cloudapi.compute.guest_agent_enable
)(vm_id=self.comp_id)
elif (
aparam_guest_agent['enabled'] is False
and self.comp_info['qemu_guest']['enabled']
):
self.compute_guest_agent_disable(vm_id=self.comp_id)
self.sdk_checkmode(
self.api.cloudapi.compute.guest_agent_disable
)(vm_id=self.comp_id)
if aparam_guest_agent['update_available_commands']:
self.compute_guest_agent_feature_update(vm_id=self.comp_id)
self.sdk_checkmode(
self.api.cloudapi.compute.guest_agent_feature_update
)(vm_id=self.comp_id)
aparam_guest_agent_exec = aparam_guest_agent['exec']
if aparam_guest_agent_exec is not None:
@@ -848,6 +860,28 @@ class decort_vm(DecortController):
vm_id=self.comp_id,
)
cpu_alignment_profile = self.aparams['cpu_alignment_profile_name']
if cpu_alignment_profile:
if (
(
self.comp_info['cpu_alignment_profile']
and cpu_alignment_profile != self.comp_info['cpu_alignment_profile']['name']
)
or not self.comp_info['cpu_alignment_profile']
):
self.sdk_checkmode(self.api.ca.compute.set_cpu_alignment_profile)(
vm_ids=[self.comp_id],
cpu_alignment_profile_name=self.aparams['cpu_alignment_profile_name'],
)
elif (
cpu_alignment_profile == ''
and self.comp_info['cpu_alignment_profile']
):
self.sdk_checkmode(self.api.ca.compute.delete_cpu_alignment_profile)(
vm_ids=[self.comp_id],
)
return
@property
@@ -868,6 +902,7 @@ class decort_vm(DecortController):
'network_interface_naming': 'networkInterfaceNaming',
'hot_resize': 'hotResize',
'os_version': 'os_version',
'clock_sync_mode': 'clock',
}
def get_nested_value(
@@ -948,7 +983,6 @@ class decort_vm(DecortController):
password="",
public_ips=[], # direct IPs; this list can be empty
private_ips=[], # IPs on ViNSes; usually, at least one IP is listed
nat_ip="", # IP of the external ViNS interface; can be empty.
tags={},
chipset="",
interfaces=[],
@@ -987,16 +1021,9 @@ class decort_vm(DecortController):
ret_dict['password'] = self.comp_info['osUsers'][0]['password']
if self.comp_info['interfaces']:
# We need a list of all ViNSes in the account, which owns this Compute
# to find a ViNS, which may have active external connection. Then
# we will save external IP address of that connection in ret_dict['nat_ip']
for iface in self.comp_info['interfaces']:
if iface['connType'] == "VXLAN": # This is ViNS connection
ret_dict['private_ips'].append(iface['ipAddress'])
# if iface['connId']
# Now we need to check if this ViNS has GW function and external connection.
# If it does - save public IP address of GW VNF in ret_dict['nat_ip']
elif iface['connType'] == "VLAN": # This is direct external network connection
ret_dict['public_ips'].append(iface['ipAddress'])
@@ -1010,6 +1037,7 @@ class decort_vm(DecortController):
ret_dict['disks'] = self.comp_info['disks']
for disk in ret_dict['disks']:
disk['read_only_mode'] = disk.pop('read_only')
if self.is_vm_boot_disk(
vm_chipset=self.comp_info['chipset'],
vm_disk=disk,
@@ -1017,6 +1045,9 @@ class decort_vm(DecortController):
# if it is a boot disk - store its size
ret_dict['disk_size'] = disk['sizeMax']
for snapshot in disk['snapshots']:
snapshot['pool_name'] = snapshot.pop('poolName')
ret_dict['chipset'] = self.comp_info['chipset']
ret_dict['interfaces'] = self.comp_info['interfaces']
@@ -1088,6 +1119,12 @@ class decort_vm(DecortController):
ret_dict['weight'] = self.comp_info['weight']
ret_dict['clock_sync_mode'] = self.comp_info['clock']
ret_dict['cpu_alignment_profile'] = self.comp_info['cpu_alignment_profile']
ret_dict['resized_online'] = self.comp_info['resizedOnline']
return ret_dict
def check_amodule_args_for_create(self):
@@ -1175,6 +1212,20 @@ class decort_vm(DecortController):
if self.check_aparam_zone_id() is False:
check_errors = True
else:
if (
self.aparams['cpu_alignment_profile_name']
and self.aparams['zone_id']
):
zone_info = self.zone_get(self.aparams['zone_id'])
if not zone_info['cpu_alignment_profiles']:
check_errors = True
self.message(
'Check for parameter "zone_id" failed:'
f' zone ID {self.aparams['zone_id']} must contain'
' cpu alignment profiles'
)
if self.aparams['guest_agent'] is not None:
check_errors = True
@@ -1230,6 +1281,17 @@ class decort_vm(DecortController):
'abort_cloning can be specified only for existing compute.'
)
if (
self.aparams['cpu_alignment_profile_name'] is not None
and self.aparams['custom_fields'] is not None
):
check_errors = True
self.message(
'Check for parameter "cpu_alignment_profile_name" failed: '
'cpu_alignment_profile_name cannot be used together '
'with parameter "custom_fields".'
)
if check_errors:
self.exit(fail=True)
@@ -1386,6 +1448,9 @@ class decort_vm(DecortController):
net_prefix=dict(
type='int',
),
enable_default_gateway=dict(
type='bool',
),
),
required_if=[
('type', 'VINS', ('id',)),
@@ -1602,6 +1667,18 @@ class decort_vm(DecortController):
abort_cloning=dict(
type='bool',
),
cpu_alignment_profile_name=dict(
type='str',
),
clock_sync_mode=dict(
type='str',
choices=[
'default',
'linux',
'windows',
'none',
],
),
),
supports_check_mode=True,
required_one_of=[
@@ -1928,6 +2005,22 @@ class decort_vm(DecortController):
if self.check_aparam_zone_id() is False:
check_errors = True
else:
if (
self.aparams['zone_id']
and self.aparams['zone_id'] != self.comp_info['zoneId']
):
zone_info = self.zone_get(self.aparams['zone_id'])
if (
not zone_info['cpu_alignment_profiles']
and self.comp_info['cpu_alignment_profile']
):
check_errors = True
self.message(
'Check for parameter "zone_id" failed: '
f'zone ID {self.aparams['zone_id']} '
'must contain cpu alignment profiles.'
)
if self.check_aparam_guest_agent() is False:
check_errors = True
@@ -1993,6 +2086,18 @@ class decort_vm(DecortController):
'Only networks of type VINS, EXTNET, DPDK, SDN, TRUNK '
'can be enabled or disabled.'
)
if (
network['enable_default_gateway'] is not None
and network['type'] != self.VMNetType.VINS.value
):
check_errors = True
self.message(
'Check for parameter '
'"networks.enable_default_gateway" failed: '
'Can not enable or disable default gateway for network'
f' ID {network['id']} and type {network['type']}. '
'Only networks of type VINS can have default gateway.'
)
if self.check_aparam_cdrom() is False:
check_errors = True
@@ -2003,6 +2108,27 @@ class decort_vm(DecortController):
if self.check_aparam_image_id() is False:
check_errors = True
if self.aparams['cpu_alignment_profile_name'] is not None:
if self.comp_info['snapSets'] or self.comp_info['custom_fields']:
check_errors = True
self.message(
'Check for parameter "cpu_alignment_profile_name" failed: '
'VM should not contain snapshots or custom fields.'
)
if (
self.aparams['boot']
and self.aparams['boot']['disk_redeploy'] is not None
and self.aparams['image_id'] is not None
):
if self.aparams['storage_policy_id'] is None:
check_errors = True
self.message(
f'Check for parameter "storage_policy_id" failed: '
'storage_policy_id must be specified when changing '
'the OS image'
)
if check_errors:
self.exit(fail=True)