This commit is contained in:
2025-05-07 14:08:17 +03:00
parent f8c32d609b
commit 4113719334
36 changed files with 10638 additions and 191 deletions

View File

@@ -111,6 +111,9 @@ class DecortAccount(DecortController):
),
),
),
description=dict(
type='str',
),
),
required_one_of=[
('id', 'name')
@@ -358,6 +361,14 @@ class DecortAccount(DecortController):
)
if set(self.facts['uniqPools']) != sep_pools:
result_args['sep_pools'] = sep_pools
aparam_desc = self.aparams['description']
if (
aparam_desc is not None
and self.facts['description'] != aparam_desc
):
result_args['description'] = aparam_desc
return result_args

View File

@@ -173,6 +173,8 @@ class decort_disk(DecortController):
ret_dict['computes'] = self.disk_info['computes']
ret_dict['gid'] = self.disk_info['gid']
ret_dict['iotune'] = self.disk_info['iotune']
ret_dict['size_available'] = self.disk_info['sizeAvailable']
ret_dict['size_used'] = self.disk_info['sizeUsed']
return ret_dict

View File

@@ -39,6 +39,7 @@ class decort_group(DecortController):
if self.group_id:
self.group_should_exist = True
self.check_amodule_args_for_change()
return
def nop(self):
@@ -74,22 +75,34 @@ class decort_group(DecortController):
return
def create(self):
chipset = self.aparams['chipset']
if chipset is None:
chipset = 'i440fx'
self.message(
msg=f'Chipset not specified, '
f'default value "{chipset}" will be used.',
warning=True,
)
self.group_id=self.group_provision(
self.bservice_id,
self.amodule.params['name'],
self.amodule.params['count'],
self.amodule.params['cpu'],
self.amodule.params['ram'],
self.amodule.params['boot_disk'],
self.amodule.params['image_id'],
self.amodule.params['driver'],
self.amodule.params['role'],
self.amodule.params['networks'],
self.amodule.params['timeoutStart'],
bs_id=self.bservice_id,
arg_name=self.amodule.params['name'],
arg_count=self.amodule.params['count'],
arg_cpu=self.amodule.params['cpu'],
arg_ram=self.amodule.params['ram'],
arg_boot_disk=self.amodule.params['boot_disk'],
arg_image_id=self.amodule.params['image_id'],
arg_driver=self.amodule.params['driver'],
arg_role=self.amodule.params['role'],
arg_network=self.amodule.params['networks'],
arg_timeout=self.amodule.params['timeoutStart'],
chipset=chipset,
)
if self.amodule.params['state'] in ('started','present'):
self.group_state(self.bservice_id,self.group_id,self.amodule.params['state'])
self.group_should_exist = True
return
def action(self):
@@ -100,13 +113,26 @@ class decort_group(DecortController):
):
self.group_state(self.bservice_id,self.group_id,self.amodule.params['state'])
if self.aparams['count'] != None:
aparam_chipset = self.aparams['chipset']
if (
self.aparams['count'] is not None
and self.aparams['count'] != len(self.group_info['computes'])
):
self.group_resize_count(
bs_id=self.bservice_id,
gr_dict=self.group_info,
desired_count=self.aparams['count'],
chipset=aparam_chipset,
)
if aparam_chipset is not None:
for vm in self.group_info['computes']:
if vm['chipset'] != aparam_chipset:
self.compute_update(
compute_id=vm['id'],
chipset=aparam_chipset,
)
for aparam_name, info_key in {'cpu': 'cpu',
'boot_disk': 'disk',
'role': 'role',
@@ -254,6 +280,13 @@ class decort_group(DecortController):
)
)
),
chipset=dict(
type='str',
choices=[
'Q35',
'i440fx',
]
),
),
supports_check_mode=True,
required_one_of=[
@@ -268,6 +301,43 @@ class decort_group(DecortController):
],
)
def check_amodule_args_for_change(self):
check_errors = False
if (
self.aparams['chipset'] is None
and self.aparams['count'] > len(self.group_info['computes'])
):
check_errors = True
self.message(
msg='Check for parameter "chipset" failed: '
'Chipset must be specified when increasing '
'VM count in group'
)
if (
self.aparams['count'] is None
or self.aparams['count'] == len(self.group_info['computes'])
):
aparam_chipset = self.aparams['chipset']
if aparam_chipset is not None:
for vm in self.group_info['computes']:
if (
vm['chipset'] != aparam_chipset
and self.group_info['techStatus'] != 'STOPPED'
and self.amodule.params['state'] != 'stopped'
):
check_errors = True
self.message(
msg=f'Check for parameter "chipset" failed: '
f'group ID {self.group_id} must be stopped '
f'to change chipset',
)
break
if check_errors:
self.exit(fail=True)
def main():
subj = decort_group()
amodule = subj.amodule

View File

@@ -121,6 +121,18 @@ class decort_k8s(DecortController):
)
self.exit(fail=True)
if (
self.aparams['master_count'] is not None
and self.aparams['master_count'] > 1
and not self.aparams['with_lb']
):
self.message(
'Check for parameter "master_count" failed: '
'master_count can be more than 1 only if the parameter '
'"with_lb" is set to True.'
)
self.exit(fail=True)
return
def package_facts(self,check_mode=False):
@@ -155,6 +167,7 @@ class decort_k8s(DecortController):
ret_dict['k8s_Masters'] = self.k8s_info['k8sGroups']['masters']
ret_dict['k8s_Workers'] = self.k8s_info['k8sGroups']['workers']
ret_dict['lb_id'] = self.k8s_info['lbId']
ret_dict['description'] = self.k8s_info['desc']
return ret_dict
@@ -358,6 +371,7 @@ class decort_k8s(DecortController):
master_count=dict(
type='int',
default=1,
choices=[1, 3, 5, 7],
),
master_cpu=dict(
type='int',

View File

@@ -1,4 +1,6 @@
#!/usr/bin/python
import re
from typing import Sequence, Any, TypeVar
DOCUMENTATION = r'''
---
@@ -12,6 +14,9 @@ from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
DefaultT = TypeVar('DefaultT')
class decort_kvmvm(DecortController):
def __init__(self):
# call superclass constructor first
@@ -73,6 +78,8 @@ class decort_kvmvm(DecortController):
if not clone_id:
clone_id = self.clone()
if self.amodule.check_mode:
self.exit()
self.comp_id, self.comp_info, self.rg_id = self._compute_get_by_id(
comp_id=clone_id,
@@ -178,8 +185,8 @@ class decort_kvmvm(DecortController):
'hp_backed must be set to True to connect a compute '
'to a DPDK network.'
)
# MTU for non-DPDK networks
for net in aparam_nets:
# MTU for non-DPDK networks
if (
net['type'] != self.VMNetType.DPDK.value
and net['mtu'] is not None
@@ -191,6 +198,28 @@ class decort_kvmvm(DecortController):
' (remove parameter "mtu" for network'
f' {net["type"]} with ID {net["id"]}).'
)
# MAC address
if net['mac'] is not None:
if net['type'] == self.VMNetType.EMPTY.value:
check_error = True
self.message(
'Check for parameter "networks.mac" failed: '
'MAC-address cannot be specified for an '
'EMPTY type network.'
)
mac_validation_result = re.match(
'[0-9a-f]{2}([:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$',
net['mac'].lower(),
)
if not mac_validation_result:
check_error = True
self.message(
'Check for parameter "networks.mac" failed: '
f'MAC-address for network ID {net["id"]} must be '
'specified in quotes and in the format '
'"XX:XX:XX:XX:XX:XX".'
)
aparam_custom_fields = self.aparams['custom_fields']
if aparam_custom_fields is not None:
@@ -215,6 +244,22 @@ class decort_kvmvm(DecortController):
'the list must contain only unique elements.'
)
aparam_state = self.aparams['state']
new_state = None
match aparam_state:
case 'halted' | 'poweredoff':
new_state = 'stopped'
case 'poweredon':
new_state = 'started'
if new_state:
self.message(
msg=f'"{aparam_state}" state is deprecated and might be '
f'removed in newer versions. '
f'Please use "{new_state}" instead.',
warning=True,
)
if check_error:
self.exit(fail=True)
@@ -265,12 +310,40 @@ class decort_kvmvm(DecortController):
# each of the following calls will abort if argument is missing
self.check_amodule_argument('cpu')
self.check_amodule_argument('ram')
aparam_boot = self.aparams['boot']
validated_bdisk_size = 0
if self.amodule.params['boot'] is not None:
boot_mode = 'bios'
loader_type = 'unknown'
if aparam_boot is not None:
validated_bdisk_size = self.amodule.params['boot'].get(
'disk_size', 0
)
if aparam_boot['mode'] is None:
self.message(
msg=self.MESSAGES.default_value_used(
param_name='boot.mode',
default_value=boot_mode
),
warning=True,
)
else:
boot_mode = aparam_boot['mode']
if aparam_boot['loader_type'] is None:
self.message(
msg=self.MESSAGES.default_value_used(
param_name='boot.loader_type',
default_value=loader_type
),
warning=True,
)
else:
loader_type = aparam_boot['loader_type']
image_id, image_facts = None, None
if self.aparam_image:
# either image_name or image_id must be present
@@ -308,7 +381,7 @@ class decort_kvmvm(DecortController):
# Once this "feature" is fixed, make sure VM is created according to the actual desired state
#
start_compute = False # change this once a workaround for the aforementioned libvirt "feature" is implemented
if self.amodule.params['state'] in ('halted', 'poweredoff'):
if self.amodule.params['state'] in ('halted', 'poweredoff', 'stopped'):
start_compute = False
if self.amodule.params['ssh_key'] and self.amodule.params['ssh_key_user'] and not self.amodule.params['ci_user_data']:
@@ -334,7 +407,6 @@ class decort_kvmvm(DecortController):
if numa_affinity is None:
numa_affinity = 'none'
chipset = self.amodule.params['chipset']
if chipset is None:
chipset = 'i440fx'
@@ -343,6 +415,28 @@ class decort_kvmvm(DecortController):
f'default value "{chipset}" will be used.',
warning=True,
)
network_interface_naming = self.aparams['network_interface_naming']
if network_interface_naming is None:
network_interface_naming = 'ens'
self.message(
msg=self.MESSAGES.default_value_used(
param_name='network_interface_naming',
default_value=network_interface_naming
),
warning=True,
)
hot_resize = self.aparams['hot_resize']
if hot_resize is None:
hot_resize = False
self.message(
msg=self.MESSAGES.default_value_used(
param_name='hot_resize',
default_value=hot_resize
),
warning=True,
)
# if we get through here, all parameters required to create new Compute instance should be at hand
# NOTE: KVM VM is created in HALTED state and must be explicitly started
@@ -360,7 +454,11 @@ class decort_kvmvm(DecortController):
cpu_pin=cpu_pin,
hp_backed=hp_backed,
numa_affinity=numa_affinity,
preferred_cpu_cores=self.amodule.params['preferred_cpu_cores'],)
preferred_cpu_cores=self.amodule.params['preferred_cpu_cores'],
boot_mode=boot_mode,
boot_loader_type=loader_type,
network_interface_naming=network_interface_naming,
hot_resize=hot_resize,)
self.comp_should_exist = True
# Originally we would have had to re-read comp_info after VM was provisioned
@@ -407,7 +505,7 @@ class decort_kvmvm(DecortController):
label=self.amodule.params['affinity_label'],)
# NOTE: see NOTE above regarding libvirt "feature" and new VMs created in HALTED state
if self.aparam_image:
if self.amodule.params['state'] not in ('halted', 'poweredoff'):
if self.amodule.params['state'] in ('poweredon', 'started'):
self.compute_powerstate(self.comp_info, 'started')
if self.aparams['custom_fields'] is None:
@@ -553,14 +651,54 @@ class decort_kvmvm(DecortController):
'description': 'desc',
'auto_start': 'autoStart',
'preferred_cpu_cores': 'preferredCpu',
'boot.mode': 'bootType',
'boot.loader_type': 'loaderType',
'network_interface_naming': 'networkInterfaceNaming',
'hot_resize': 'hotResize',
}
def get_nested_value(
d: dict,
keys: Sequence[str],
default: DefaultT | None = None,
) -> Any | DefaultT:
if not keys:
raise ValueError
key = keys[0]
if key not in d:
return default
value = d[key]
if len(keys) > 1:
if isinstance(value, dict):
nested_d = value
return get_nested_value(
d=nested_d,
keys=keys[1:],
default=default,
)
if value is None:
return default
raise ValueError(
f'The key {key} found, but its value is not a dictionary.'
)
return value
for aparam_name, comp_field_name in params_to_check.items():
aparam_value = self.amodule.params[aparam_name]
if (
aparam_value is not None
and aparam_value != self.comp_info[comp_field_name]
):
result_args[aparam_name] = aparam_value
aparam_value = get_nested_value(
d=self.aparams,
keys=aparam_name.split('.'),
)
comp_value = get_nested_value(
d=self.comp_info,
keys=comp_field_name.split('.'),
)
if aparam_value is not None and aparam_value != comp_value:
result_args[aparam_name.replace('.', '_')] = (
aparam_value
)
return result_args
@@ -679,15 +817,49 @@ class decort_kvmvm(DecortController):
ret_dict['clones'] = self.comp_info['clones']
ret_dict['clone_reference'] = self.comp_info['cloneReference']
ret_dict['boot_mode'] = self.comp_info['bootType']
ret_dict['boot_loader_type'] = self.comp_info['loaderType']
ret_dict['network_interface_naming'] = self.comp_info[
'networkInterfaceNaming'
]
ret_dict['hot_resize'] = self.comp_info['hotResize']
ret_dict['pinned_to_stack'] = self.comp_info['pinnedToStack']
ret_dict['affinity_label'] = self.comp_info['affinityLabel']
ret_dict['affinity_rules'] = self.comp_info['affinityRules']
ret_dict['anti_affinity_rules'] = self.comp_info['antiAffinityRules']
return ret_dict
def check_amodule_args_for_create(self):
check_errors = False
# Check for unacceptable parameters for a blank Compute
if (
self.aparams['image_id'] is not None
or self.aparams['image_name'] is not None
):
self.aparam_image = True
for param in (
'network_interface_naming',
'hot_resize',
):
if self.aparams[param] is not None:
check_errors = True
self.message(
f'Check for parameter "{param}" failed: '
'parameter can be specified only for a blank VM.'
)
if self.aparams['boot'] is not None:
for param in ('mode', 'loader_type'):
if self.aparams['boot'][param] is not None:
check_errors = True
self.message(
f'Check for parameter "boot.{param}" failed: '
'parameter can be specified only for a blank VM.'
)
else:
self.aparam_image = False
if (
@@ -696,14 +868,15 @@ class decort_kvmvm(DecortController):
'present',
'poweredoff',
'halted',
'stopped',
)
):
check_errors = True
self.message(
'Check for parameter "state" failed: '
'state for a blank Compute must be either '
'"present", "poweredoff" or "halted".'
'"present" or "stopped".'
)
self.exit(fail=True)
for parameter in (
'ssh_key',
@@ -711,38 +884,41 @@ class decort_kvmvm(DecortController):
'ci_user_data',
):
if self.aparams[parameter] is not None:
check_errors = True
self.message(
f'Check for parameter "{parameter}" failed: '
f'"image_id" or "image_name" must be specified '
f'to set {parameter}.'
)
self.exit(fail=True)
if (
self.aparams['sep_id'] is not None
and self.aparams['boot'] is None
and self.aparams['boot']['disk_size'] is None
):
check_errors = True
self.message(
'Check for parameter "sep_id" failed: '
'"image_id" or "image_name" or "boot.disk_size" '
'must be specified to set sep_id.'
)
self.exit(fail=True)
if self.aparams['rollback_to'] is not None:
check_errors = True
self.message(
'Check for parameter "rollback_to" failed: '
'rollback_to can be specified only for existing compute.'
)
self.exit(fail=True)
if self.aparam_networks_has_dpdk and not self.aparams['hp_backed']:
check_errors = True
self.message(
'Check for parameter "networks" failed:'
' hp_backed must be set to True to connect a compute'
' to a DPDK network.'
)
if check_errors:
self.exit(fail=True)
@property
@@ -769,6 +945,21 @@ class decort_kvmvm(DecortController):
disk_size=dict(
type='int',
),
mode=dict(
type='str',
choices=[
'bios',
'uefi',
],
),
loader_type=dict(
type='str',
choices=[
'windows',
'linux',
'unknown',
],
),
),
),
sep_id=dict(
@@ -840,6 +1031,9 @@ class decort_kvmvm(DecortController):
mtu=dict(
type='int',
),
mac=dict(
type='str',
),
),
required_if=[
('type', 'VINS', ('id',)),
@@ -892,6 +1086,8 @@ class decort_kvmvm(DecortController):
'poweredoff',
'halted',
'poweredon',
'stopped',
'started',
'present',
],
),
@@ -974,6 +1170,16 @@ class decort_kvmvm(DecortController):
),
),
),
network_interface_naming=dict(
type='str',
choices=[
'ens',
'eth',
],
),
hot_resize=dict(
type='bool',
),
),
supports_check_mode=True,
required_one_of=[
@@ -1069,12 +1275,14 @@ class decort_kvmvm(DecortController):
if (
not comp_info['imageId']
and self.amodule.params['state'] in ('poweredon', 'paused')
and self.amodule.params['state'] in (
'poweredon', 'paused', 'started',
)
):
check_errors = True
self.message(
'Check for parameter "state" failed: '
'state for a blank Compute can not be "poweredon" or "paused".'
'state for a blank Compute can not be "started" or "paused".'
)
is_vm_stopped_or_will_be_stopped = (
@@ -1083,14 +1291,14 @@ class decort_kvmvm(DecortController):
and (
self.amodule.params['state'] is None
or self.amodule.params['state'] in (
'halted', 'poweredoff', 'present',
'halted', 'poweredoff', 'present', 'stopped',
)
)
)
or (
comp_info['techStatus'] != 'STOPPED'
and self.amodule.params['state'] in (
'halted', 'poweredoff',
'halted', 'poweredoff', 'stopped',
)
)
)
@@ -1120,6 +1328,7 @@ class decort_kvmvm(DecortController):
'cpu_pin': 'cpupin',
'hp_backed': 'hpBacked',
'numa_affinity': 'numaAffinity',
'hot_resize': 'hotResize',
}
for param_name, comp_field_name in params_to_check.items():
if (
@@ -1159,13 +1368,13 @@ class decort_kvmvm(DecortController):
and (
self.amodule.params['state'] is None
or self.amodule.params['state'] in (
'poweredon', 'present',
'poweredon', 'present', 'started',
)
)
)
or (
comp_info['techStatus'] != 'STARTED'
and self.amodule.params['state'] == 'poweredon'
and self.amodule.params['state'] in ('poweredon', 'started')
)
)
@@ -1179,30 +1388,55 @@ class decort_kvmvm(DecortController):
aparam_disks = self.aparams['disks']
if aparam_disks is not None:
if self.comp_info['snapSets']:
match aparam_disks['mode']:
case 'detach' | 'delete':
check_errors = True
self.message(
f'Check for parameter "disks" failed: '
f'cannot {aparam_disks["mode"]} disks for '
f'Compute ID {self.comp_id} while snapshots '
f'exist in compute.'
)
case 'match':
comp_disk_ids = {
disk['id'] for disk in self.comp_info['disks']
}
disks = set(aparam_disks['ids'])
disks_to_detach = comp_disk_ids - disks
if disks_to_detach:
check_errors = True
self.message(
f'Check for parameter "disks" failed: '
f'disks {disks_to_detach} cannot be detached '
f'from Compute ID {self.comp_id} while '
f'snapshots exist in compute.'
)
aparam_disks_ids = aparam_disks['ids']
comp_boot_disk_id = None
for comp_disk in self.comp_info['disks']:
if comp_disk['type'] == 'B':
comp_boot_disk_id = comp_disk['id']
break
disks_to_detach = []
match aparam_disks['mode']:
case 'detach' | 'delete':
disks_to_detach = aparam_disks_ids
case 'match':
comp_disk_ids = {
disk['id'] for disk in self.comp_info['disks']
}
disks = set(aparam_disks_ids)
disks_to_detach = comp_disk_ids - disks
if (
comp_boot_disk_id is not None
and comp_boot_disk_id in disks_to_detach
and not is_vm_stopped_or_will_be_stopped
):
check_errors = True
self.message(
f'Check for parameter "disks" failed: '
f'VM ID {comp_id} must be stopped to detach '
f'boot disk ID {comp_boot_disk_id}.'
)
if self.comp_info['snapSets'] and disks_to_detach:
check_errors = True
self.message(
f'Check for parameter "disks" failed: '
f'cannot detach disks {disks_to_detach} from '
f'Compute ID {self.comp_id} while snapshots exist.'
)
if (
(
self.aparams['cpu'] is not None
and self.aparams['cpu'] != comp_info['cpus']
) or (
self.aparams['ram'] is not None
and self.aparams['ram'] != comp_info['ram']
)
) and not (self.aparams['hot_resize'] or comp_info['hotResize']):
check_errors = True
self.message(
'Check for parameters "cpu" and "ram" failed: '
'Hot resize must be enabled to change CPU or RAM.'
)
if check_errors:
self.exit(fail=True)
@@ -1323,7 +1557,8 @@ def main():
subj.destroy()
else:
if amodule.params['state'] in (
'paused', 'poweredon', 'poweredoff', 'halted'
'paused', 'poweredon', 'poweredoff',
'halted', 'started', 'stopped',
):
subj.compute_powerstate(
comp_facts=subj.comp_info,
@@ -1331,7 +1566,7 @@ def main():
)
subj.modify(arg_wait_cycles=7)
elif subj.comp_info['status'] == "DELETED":
if amodule.params['state'] in ('present', 'poweredon'):
if amodule.params['state'] in ('present', 'poweredon', 'started'):
# TODO - check if restore API returns VM ID (similarly to VM create API)
subj.compute_restore(comp_id=subj.comp_id)
# TODO - do we need updated comp_info to manage port forwards and size after VM is restored?
@@ -1345,10 +1580,15 @@ def main():
# subj.nop()
# subj.comp_should_exist = False
subj.destroy()
elif amodule.params['state'] in ('paused', 'poweredoff', 'halted'):
elif amodule.params['state'] in (
'paused', 'poweredoff', 'halted', 'stopped'
):
subj.error()
elif subj.comp_info['status'] == "DESTROYED":
if amodule.params['state'] in ('present', 'poweredon', 'poweredoff', 'halted'):
if amodule.params['state'] in (
'present', 'poweredon', 'poweredoff',
'halted', 'started', 'stopped',
):
subj.create() # this call will also handle data disk & network connection
elif amodule.params['state'] == 'absent':
subj.nop()
@@ -1363,7 +1603,10 @@ def main():
# If requested state is 'absent' - nothing to do
if state == 'absent':
subj.nop()
elif state in ('present', 'poweredon', 'poweredoff', 'halted'):
elif state in (
'present', 'poweredon', 'poweredoff',
'halted', 'started', 'stopped',
):
subj.create() # this call will also handle data disk & network connection
elif state == 'paused':
subj.error()

View File

@@ -72,13 +72,61 @@ class decort_osimage(DecortController):
def decort_image_create(self,amodule):
aparam_boot = self.aparams['boot']
boot_mode = 'bios'
loader_type = 'unknown'
if aparam_boot is not None:
if aparam_boot['mode'] is None:
self.message(
msg=self.MESSAGES.default_value_used(
param_name='boot.mode',
default_value=boot_mode
),
warning=True,
)
else:
boot_mode = aparam_boot['mode']
if aparam_boot['loader_type'] is None:
self.message(
msg=self.MESSAGES.default_value_used(
param_name='boot.loader_type',
default_value=loader_type
),
warning=True,
)
else:
loader_type = aparam_boot['loader_type']
network_interface_naming = self.aparams['network_interface_naming']
if network_interface_naming is None:
network_interface_naming = 'ens'
self.message(
msg=self.MESSAGES.default_value_used(
param_name='network_interface_naming',
default_value=network_interface_naming
),
warning=True,
)
hot_resize = self.aparams['hot_resize']
if hot_resize is None:
hot_resize = False
self.message(
msg=self.MESSAGES.default_value_used(
param_name='hot_resize',
default_value=hot_resize
),
warning=True,
)
# function that creates OS image
image_facts = self.image_create(img_name=self.validated_image_name,
url=amodule.params['url'],
gid=amodule.params['gid'],
boottype=amodule.params['boottype'],
imagetype=amodule.params['imagetype'],
hotresize=amodule.params['hotresize'],
boot_mode=boot_mode,
boot_loader_type=loader_type,
hot_resize=hot_resize,
username=amodule.params['image_username'],
password=amodule.params['image_password'],
account_Id=self.validated_account_id,
@@ -86,7 +134,8 @@ class decort_osimage(DecortController):
passwordDL=amodule.params['passwordDL'],
sepId=amodule.params['sepId'],
poolName=amodule.params['poolName'],
drivers=amodule.params['drivers'])
drivers=amodule.params['drivers'],
network_interface_naming=network_interface_naming)
self.result['changed'] = True
return image_facts
@@ -126,7 +175,11 @@ class decort_osimage(DecortController):
image_id, image_facts = self.decort_virt_image_find(amodule)
return image_id, image_facts
def decort_osimage_package_facts(arg_osimage_facts, arg_check_mode=False):
@staticmethod
def decort_osimage_package_facts(
arg_osimage_facts: dict | None,
arg_check_mode=False,
):
"""Package a dictionary of OS image according to the decort_osimage module specification. This
dictionary will be returned to the upstream Ansible engine at the completion of the module run.
@@ -154,13 +207,26 @@ class decort_osimage(DecortController):
ret_dict['id'] = arg_osimage_facts['id']
ret_dict['name'] = arg_osimage_facts['name']
ret_dict['size'] = arg_osimage_facts['size']
ret_dict['type'] = arg_osimage_facts['type']
# ret_dict['arch'] = arg_osimage_facts['architecture']
ret_dict['sep_id'] = arg_osimage_facts['sepId']
ret_dict['pool'] = arg_osimage_facts['pool']
ret_dict['state'] = arg_osimage_facts['status']
ret_dict['linkto'] = arg_osimage_facts['linkTo']
ret_dict['accountId'] = arg_osimage_facts['accountId']
ret_dict['boot_mode'] = arg_osimage_facts['bootType']
ret_dict['boot_loader_type'] = ''
match arg_osimage_facts['type']:
case 'cdrom' | 'virtual' as type:
ret_dict['type'] = type
case _ as boot_loader_type:
ret_dict['type'] = 'template'
ret_dict['boot_loader_type'] = boot_loader_type
ret_dict['network_interface_naming'] = arg_osimage_facts[
'networkInterfaceNaming'
]
ret_dict['hot_resize'] = arg_osimage_facts['hotResize']
return ret_dict
@property
@@ -207,14 +273,6 @@ class decort_osimage(DecortController):
type='str',
default='KVM_X86',
),
imagetype=dict(
type='str',
default='linux',
),
boottype=dict(
type='str',
default='uefi',
),
url=dict(
type='str',
),
@@ -229,9 +287,8 @@ class decort_osimage(DecortController):
poolName=dict(
type='str',
),
hotresize=dict(
hot_resize=dict(
type='bool',
default=False,
),
image_username=dict(
type='str',
@@ -245,6 +302,33 @@ class decort_osimage(DecortController):
passwordDL=dict(
type='str',
),
boot=dict(
type='dict',
options=dict(
mode=dict(
type='str',
choices=[
'bios',
'uefi',
],
),
loader_type=dict(
type='str',
choices=[
'windows',
'linux',
'unknown',
],
),
),
),
network_interface_naming=dict(
type='str',
choices=[
'ens',
'eth',
],
),
),
supports_check_mode=True,
)

View File

@@ -117,29 +117,29 @@ class DecortUserInfo(DecortController):
start=dict(
type='dict',
options=dict(
unix=dict(
timestamp=dict(
type='int',
),
date_time=dict(
datetime=dict(
type='str',
),
),
mutually_exclusive=[
('unix', 'date_time'),
('timestamp', 'datetime'),
],
),
end=dict(
type='dict',
options=dict(
unix=dict(
timestamp=dict(
type='int',
),
date_time=dict(
datetime=dict(
type='str',
),
),
mutually_exclusive=[
('unix', 'date_time'),
('timestamp', 'datetime'),
],
),
),
@@ -160,6 +160,23 @@ class DecortUserInfo(DecortController):
),
),
),
sorting=dict(
type='dict',
options=dict(
asc=dict(
type='bool',
default=True,
),
field=dict(
type='str',
choices=[
e.value
for e in self.AuditsSortableField
],
required=True,
),
),
),
),
),
objects_search=dict(
@@ -184,7 +201,7 @@ class DecortUserInfo(DecortController):
match self.aparams['audits']:
case {'filter': {'time':
{'start': {'date_time': str() as dt_str}}
{'start': {'datetime': str() as dt_str}}
}
}:
if self.dt_str_to_sec(dt_str=dt_str) is None:
@@ -192,7 +209,7 @@ class DecortUserInfo(DecortController):
check_error = True
match self.aparams['audits']:
case {'filter': {'time':
{'end': {'date_time': str() as dt_str}}
{'end': {'datetime': str() as dt_str}}
}
}:
if self.dt_str_to_sec(dt_str=dt_str) is None:
@@ -283,16 +300,16 @@ class DecortUserInfo(DecortController):
mapped_args['max_status_code'] = max_status_code
match input_args_filter['time']:
case {'start': {'unix': int() as start_unix_time}}:
case {'start': {'timestamp': int() as start_unix_time}}:
mapped_args['start_unix_time'] = start_unix_time
case {'start': {'date_time': str() as start_dt_str}}:
case {'start': {'datetime': str() as start_dt_str}}:
mapped_args['start_unix_time'] = self.dt_str_to_sec(
dt_str=start_dt_str
)
match input_args_filter['time']:
case {'end': {'unix': int() as end_unix_time}}:
case {'end': {'timestamp': int() as end_unix_time}}:
mapped_args['end_unix_time'] = end_unix_time
case {'end': {'date_time': str() as end_dt_str}}:
case {'end': {'datetime': str() as end_dt_str}}:
mapped_args['end_unix_time'] = self.dt_str_to_sec(
dt_str=end_dt_str
)
@@ -302,6 +319,16 @@ class DecortUserInfo(DecortController):
mapped_args['page_number'] = input_args_pagination['number']
mapped_args['page_size'] = input_args_pagination['size']
input_args_sorting = input_args['sorting']
if input_args_sorting:
mapped_args['sort_by_asc'] = input_args_sorting['asc']
input_args_sorting_field = input_args_sorting['field']
if input_args_sorting_field:
mapped_args['sort_by_field'] = (
self.AuditsSortableField(input_args_sorting_field)
)
return mapped_args
def run(self):