7.2.0
This commit is contained in:
@@ -1130,81 +1130,77 @@ class DecortController(object):
|
||||
break
|
||||
return
|
||||
|
||||
def compute_data_disks(self, comp_dict, new_data_disks):
|
||||
"""Manage attachment of data disks to the Compute instance.
|
||||
@waypoint
|
||||
@checkmode
|
||||
def compute_disks(self, comp_dict: dict, aparam_disks: dict):
|
||||
disks = set(aparam_disks['ids'])
|
||||
mode = aparam_disks['mode']
|
||||
|
||||
@param (dict) comp_dict: dictionary with Compute facts, that identifies the Compute instance
|
||||
to manage data disks for.
|
||||
@param (list of int) new_data_disks: list of integer IDs for the disks that must be attached to
|
||||
this Compute instance. If some disk IDs appear in this list, but are not present in comp_dict,
|
||||
these disks will be attached. Vice versa, if some disks appear in comp_dict but are not present
|
||||
in data_disks, such disks will be detached.
|
||||
comp_disks = {disk['id'] for disk in comp_dict['disks']}
|
||||
disks_to_attach = set()
|
||||
disks_to_detach = set()
|
||||
disks_to_delete = set()
|
||||
match mode:
|
||||
case 'update':
|
||||
disks_to_attach = disks - comp_disks
|
||||
case 'detach':
|
||||
disks_to_detach = disks & comp_disks
|
||||
case 'delete':
|
||||
disks_to_delete = disks & comp_disks
|
||||
case 'match':
|
||||
disks_to_attach = disks - comp_disks
|
||||
disks_to_detach = comp_disks - disks
|
||||
|
||||
Note:
|
||||
1) you cannot control boot disk attachment, so including this Compute's boot disk ID
|
||||
into data_disk list will have no effect (as well as not listing it there).
|
||||
2) this function may modify data_disks by removing from it an ID that corresponds to
|
||||
this Compute's boot disk (if found).
|
||||
3) In view of #2, upstream code may need to reread compute facts (com_dict) so that it
|
||||
contains updated information about attached disks.
|
||||
"""
|
||||
for disk_id in disks_to_attach:
|
||||
api_params = {
|
||||
'computeId': comp_dict['id'],
|
||||
'diskId': disk_id,
|
||||
'diskType': 'D',
|
||||
}
|
||||
self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/diskAttach',
|
||||
arg_params=api_params,
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "compute_data_disks")
|
||||
for disk_id in disks_to_detach:
|
||||
api_params = {
|
||||
'computeId': comp_dict['id'],
|
||||
'diskId': disk_id,
|
||||
}
|
||||
self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/diskDetach',
|
||||
arg_params=api_params,
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
if self.amodule.check_mode:
|
||||
self.result['failed'] = False
|
||||
self.result['msg'] = ("compute_data_disks() in check mode: managing data disks on Compute "
|
||||
"ID {} was requested.").format(comp_dict['id'])
|
||||
return
|
||||
for disk_id in disks_to_delete:
|
||||
api_params = {
|
||||
'computeId': comp_dict['id'],
|
||||
'diskId': disk_id,
|
||||
}
|
||||
self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/diskDel',
|
||||
arg_params=api_params,
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
bdisk_id = 0
|
||||
current_list = []
|
||||
detach_list = []
|
||||
attach_list = []
|
||||
|
||||
# 'data_disks' argument for decort_kvmvm module expects list of integer disk IDs.
|
||||
# However, if the value for disk ID comes via Jinja templating like this:
|
||||
# data_disks:
|
||||
# - "{{ my_disk.facts.id }}" <= will come as string, which is WRONG!!!
|
||||
# - 4571 <= no Jinja templae, will come as int - OK
|
||||
#
|
||||
# then all values when entering this method will be of type string. We need to
|
||||
# explicitly cast int type on all of them.
|
||||
if new_data_disks is not None:
|
||||
for idx, repair in enumerate(new_data_disks):
|
||||
new_data_disks[idx] = int(repair)
|
||||
else:
|
||||
new_data_disks = []
|
||||
|
||||
for disk in comp_dict['disks']:
|
||||
if disk['type'] == 'B':
|
||||
bdisk_id = disk['id']
|
||||
if bdisk_id in new_data_disks:
|
||||
# If boot disk ID is listed in data_disks - remove it
|
||||
new_data_disks.remove(bdisk_id)
|
||||
elif disk['type'] == 'D':
|
||||
# build manipulation sets for 'D' type disks only
|
||||
current_list.append(disk['id'])
|
||||
if disk['id'] not in new_data_disks:
|
||||
detach_list.append(disk['id'])
|
||||
|
||||
attach_list = [did for did in new_data_disks if did not in current_list]
|
||||
|
||||
for did in detach_list:
|
||||
api_params = dict(computeId=comp_dict['id'], diskId=did)
|
||||
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/diskDetach", api_params)
|
||||
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
||||
self.result['changed'] = True
|
||||
|
||||
for did in attach_list:
|
||||
api_params = dict(computeId=comp_dict['id'], diskId=did)
|
||||
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/diskAttach", api_params)
|
||||
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
||||
self.result['changed'] = True
|
||||
|
||||
self.result['failed'] = False
|
||||
|
||||
return
|
||||
@waypoint
|
||||
@checkmode
|
||||
def compute_boot_disk(self, comp_id: int, boot_disk: int):
|
||||
api_params = {
|
||||
'computeId': comp_id,
|
||||
'diskId': boot_disk,
|
||||
}
|
||||
self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/bootDiskSet',
|
||||
arg_params=api_params,
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
def compute_delete(self, comp_id, permanently=False,detach=True):
|
||||
"""Delete a Compute instance identified by its ID. It is assumed that the Compute with the specified
|
||||
@@ -1233,7 +1229,12 @@ class DecortController(object):
|
||||
|
||||
return
|
||||
|
||||
def _compute_get_by_id(self, comp_id, need_custom_fields: bool = False):
|
||||
def _compute_get_by_id(
|
||||
self,
|
||||
comp_id,
|
||||
need_custom_fields: bool = False,
|
||||
need_console_url: bool = False,
|
||||
):
|
||||
"""Helper function that locates compute instance by ID and returns Compute facts.
|
||||
|
||||
@param (int) comp_id: ID of the Compute instance to find and return facts for.
|
||||
@@ -1266,16 +1267,23 @@ class DecortController(object):
|
||||
)
|
||||
ret_comp_dict['custom_fields'] = custom_fields
|
||||
|
||||
if need_console_url and ret_comp_dict['techStatus'] == 'STARTED':
|
||||
console_url = self.compute_get_console_url(
|
||||
compute_id=ret_comp_id,
|
||||
)
|
||||
ret_comp_dict['console_url'] = console_url
|
||||
|
||||
else:
|
||||
self.result['warning'] = ("compute_get_by_id(): failed to get Compute by ID {}. HTTP code {}, "
|
||||
"response {}.").format(comp_id, api_resp.status_code, api_resp.reason)
|
||||
|
||||
return ret_comp_id, ret_comp_dict, ret_rg_id
|
||||
|
||||
def compute_find(self, comp_id,
|
||||
def compute_find(self, comp_id: int = 0,
|
||||
comp_name="", rg_id=0,
|
||||
check_state=True,
|
||||
need_custom_fields: bool = False):
|
||||
need_custom_fields: bool = False,
|
||||
need_console_url: bool = False):
|
||||
"""Tries to find Compute instance according to the specified parameters. On success returns non-zero
|
||||
Compute ID and a dictionary with Compute details, or 0 for ID and None for the dictionary on failure.
|
||||
|
||||
@@ -1312,6 +1320,7 @@ class DecortController(object):
|
||||
self._compute_get_by_id(
|
||||
comp_id=comp_id,
|
||||
need_custom_fields=need_custom_fields,
|
||||
need_console_url=need_console_url,
|
||||
)
|
||||
)
|
||||
if not ret_comp_id:
|
||||
@@ -1352,6 +1361,7 @@ class DecortController(object):
|
||||
_, ret_comp_dict, _ = self._compute_get_by_id(
|
||||
comp_id=ret_comp_id,
|
||||
need_custom_fields=need_custom_fields,
|
||||
need_console_url=need_console_url,
|
||||
)
|
||||
break
|
||||
|
||||
@@ -1436,7 +1446,7 @@ class DecortController(object):
|
||||
def kvmvm_provision(self, rg_id,
|
||||
comp_name,
|
||||
cpu, ram,
|
||||
boot_disk,
|
||||
boot_disk_size,
|
||||
image_id,
|
||||
chipset: Literal['Q35', 'i440fx'] = 'i440fx',
|
||||
description="",
|
||||
@@ -1478,12 +1488,12 @@ class DecortController(object):
|
||||
'name': comp_name,
|
||||
'cpu': cpu,
|
||||
'ram': ram,
|
||||
'bootDisk': boot_disk,
|
||||
'bootDisk': boot_disk_size,
|
||||
'sepId': sep_id,
|
||||
'pool': pool_name,
|
||||
'interfaces': '[]', # we create VM without any network connections
|
||||
'chipset': chipset,
|
||||
'withoutBootDisk': not boot_disk,
|
||||
'withoutBootDisk': not boot_disk_size,
|
||||
'preferredCpu': preferred_cpu_cores,
|
||||
}
|
||||
if description:
|
||||
@@ -2096,6 +2106,48 @@ class DecortController(object):
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
@waypoint
|
||||
@checkmode
|
||||
def compute_clone(
|
||||
self,
|
||||
compute_id: int,
|
||||
name: str,
|
||||
snapshot_timestamp: int | None = None,
|
||||
snapshot_name: str | None = None,
|
||||
snapshot_datetime: str | None = None,
|
||||
force: bool = False,
|
||||
):
|
||||
_snapshot_timestamp = snapshot_timestamp
|
||||
if snapshot_datetime:
|
||||
_snapshot_timestamp = self.dt_str_to_sec(dt_str=snapshot_datetime)
|
||||
|
||||
api_params = {
|
||||
'computeId': compute_id,
|
||||
'name': name,
|
||||
'force': force,
|
||||
'snapshotName': snapshot_name,
|
||||
'snapshotTimestamp': _snapshot_timestamp,
|
||||
}
|
||||
|
||||
api_resp = self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/clone',
|
||||
arg_params=api_params,
|
||||
)
|
||||
self.set_changed()
|
||||
return int(api_resp.content)
|
||||
|
||||
@waypoint
|
||||
def compute_get_console_url(self, compute_id: int):
|
||||
api_response = self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/compute/getConsoleUrl',
|
||||
arg_params={
|
||||
'computeId': compute_id,
|
||||
},
|
||||
)
|
||||
return api_response.text
|
||||
|
||||
###################################
|
||||
# OS image manipulation methods
|
||||
###################################
|
||||
@@ -2616,7 +2668,7 @@ class DecortController(object):
|
||||
|
||||
# TODO: this method will not work in its current implementation. Update it for new .../rg/update specs.
|
||||
|
||||
def rg_update(self, arg_rg_dict, arg_quotas, arg_res_types, arg_newname, arg_sep_pools):
|
||||
def rg_update(self, arg_rg_dict, arg_quotas, arg_res_types, arg_newname, arg_sep_pools, arg_desc: str | None = None):
|
||||
"""Manage quotas for an existing RG.
|
||||
|
||||
@param arg_rg_dict: dictionary with RG facts as returned by rg_find(...) method or .../rg/get API
|
||||
@@ -2697,6 +2749,10 @@ class DecortController(object):
|
||||
api_params['clearUniqPools'] = True
|
||||
update_required = True
|
||||
|
||||
if arg_desc is not None and arg_desc != arg_rg_dict['desc']:
|
||||
api_params['desc'] = arg_desc
|
||||
update_required = True
|
||||
|
||||
if update_required:
|
||||
self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/update", api_params)
|
||||
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
||||
@@ -4518,7 +4574,7 @@ class DecortController(object):
|
||||
|
||||
return 0, None
|
||||
|
||||
def disk_create(self, accountId, name, description, size, type, iops, sep_id, pool):
|
||||
def disk_create(self, accountId, name, description, size, iops, sep_id, pool):
|
||||
"""Provision Disk according to the specified arguments.
|
||||
Note that disks created by this method will be of type 'D' (data disks).
|
||||
If critical error occurs the embedded call to API function will abort further execution
|
||||
@@ -4542,7 +4598,6 @@ class DecortController(object):
|
||||
name=name,
|
||||
description=description,
|
||||
size=size,
|
||||
type=type,
|
||||
iops=iops,
|
||||
sep_id=sep_id,
|
||||
pool=pool )
|
||||
@@ -5140,6 +5195,7 @@ class DecortController(object):
|
||||
description,
|
||||
extnet_only,
|
||||
master_chipset: Literal['Q35', 'i440fx'] = 'i440fx',
|
||||
lb_sysctl: dict | None = None,
|
||||
):
|
||||
|
||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "k8s_provision")
|
||||
@@ -5185,6 +5241,9 @@ class DecortController(object):
|
||||
userData=json.dumps(default_worker['ci_user_data']),
|
||||
extnetOnly=extnet_only,
|
||||
chipset=master_chipset,
|
||||
lbSysctlParams=lb_sysctl and json.dumps(
|
||||
{k: str(v) for k, v in lb_sysctl.items()}
|
||||
),
|
||||
)
|
||||
|
||||
upload_files = None
|
||||
@@ -5903,7 +5962,7 @@ class DecortController(object):
|
||||
self.amodule.fail_json(**self.result)
|
||||
|
||||
return 0, None
|
||||
def lb_provision(self,lb_name,rg_id,vins_id,ext_net_id,ha_status,description,start=True):
|
||||
def lb_provision(self,lb_name,rg_id,vins_id,ext_net_id,ha_status,description,start=True, sysctl: dict | None = None):
|
||||
"""Provision LB according to the specified arguments.
|
||||
If critical error occurs the embedded call to API function will abort further execution of
|
||||
the script and relay error to Ansible.
|
||||
@@ -5932,7 +5991,10 @@ class DecortController(object):
|
||||
vinsId=vins_id,
|
||||
highlyAvailable=ha_status,
|
||||
start=start,
|
||||
desc=description
|
||||
desc=description,
|
||||
sysctlParams=sysctl and json.dumps(
|
||||
{k: str(v) for k, v in sysctl.items()}
|
||||
),
|
||||
)
|
||||
api_resp = self.decort_api_call(requests.post, api_url, api_params)
|
||||
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
||||
@@ -6259,8 +6321,15 @@ class DecortController(object):
|
||||
api_resp = self.decort_api_call(requests.post, api_url, api_params)
|
||||
self.result['changed'] = True
|
||||
|
||||
def lb_update(self,prime,front_ha_ip,back_ha_ip,lb_backends=[],lb_frontends=[],mod_backends=[],mod_servers=[],mod_frontends=[]):
|
||||
|
||||
def lb_update(
|
||||
self,
|
||||
lb_facts: dict,
|
||||
aparam_backends: list | None,
|
||||
aparam_frontends: list | None,
|
||||
aparam_servers: list | None,
|
||||
aparam_sysctl: dict | None,
|
||||
):
|
||||
|
||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_update")
|
||||
|
||||
if self.amodule.check_mode:
|
||||
@@ -6271,11 +6340,13 @@ class DecortController(object):
|
||||
self.result['msg'] = result_msg
|
||||
return
|
||||
|
||||
if mod_backends is None:
|
||||
lb_backends = lb_facts['backends']
|
||||
lb_frontends = lb_facts['frontends']
|
||||
if aparam_backends is None:
|
||||
upd_back_list = [back['name'] for back in lb_backends]
|
||||
else:
|
||||
#lists from module and cloud
|
||||
mod_backs_list = [back['name'] for back in mod_backends]
|
||||
mod_backs_list = [back['name'] for back in aparam_backends]
|
||||
lb_backs_list = [back['name'] for back in lb_backends]
|
||||
#ADD\DEL\UPDATE LISTS OF BACKENDS
|
||||
del_list_backs = set(lb_backs_list).difference(mod_backs_list)
|
||||
@@ -6294,21 +6365,21 @@ class DecortController(object):
|
||||
if add_back_list:
|
||||
self._lb_create_backends(
|
||||
add_back_list,
|
||||
mod_backends,
|
||||
mod_servers
|
||||
aparam_backends,
|
||||
aparam_servers
|
||||
)
|
||||
|
||||
if upd_back_list:
|
||||
if mod_backends is not None or mod_servers is not None:
|
||||
if aparam_backends is not None or aparam_servers is not None:
|
||||
self._lb_update_backends(
|
||||
upd_back_list,
|
||||
lb_backends,
|
||||
mod_backends,
|
||||
mod_servers,
|
||||
aparam_backends,
|
||||
aparam_servers,
|
||||
)
|
||||
|
||||
if mod_frontends is not None:
|
||||
mod_front_list = [front['name'] for front in mod_frontends]
|
||||
if aparam_frontends is not None:
|
||||
mod_front_list = [front['name'] for front in aparam_frontends]
|
||||
lb_front_list = [front['name'] for front in lb_frontends]
|
||||
|
||||
del_list_fronts = set(lb_front_list).difference(mod_front_list)
|
||||
@@ -6318,6 +6389,8 @@ class DecortController(object):
|
||||
if del_list_fronts:
|
||||
self._lb_delete_fronts(del_list_fronts)
|
||||
|
||||
front_ha_ip = lb_facts['frontendHAIP']
|
||||
back_ha_ip = lb_facts['backendHAIP']
|
||||
#set bind_ip
|
||||
if front_ha_ip != "":
|
||||
bind_ip = front_ha_ip
|
||||
@@ -6326,16 +6399,25 @@ class DecortController(object):
|
||||
bind_ip = back_ha_ip
|
||||
|
||||
if front_ha_ip == "" and back_ha_ip == "":
|
||||
prime = lb_facts['primaryNode']
|
||||
if prime["frontendIp"] != "":
|
||||
bind_ip = prime["frontendIp"]
|
||||
else:
|
||||
bind_ip = prime["backendIp"]
|
||||
|
||||
if add_list_fronts:
|
||||
self._lb_add_fronts(add_list_fronts,mod_frontends,bind_ip)
|
||||
self._lb_add_fronts(add_list_fronts,aparam_frontends,bind_ip)
|
||||
if upd_front_list:
|
||||
self._lb_update_fronts(upd_front_list,lb_frontends,mod_frontends,bind_ip)
|
||||
|
||||
self._lb_update_fronts(upd_front_list,lb_frontends,aparam_frontends,bind_ip)
|
||||
|
||||
if aparam_sysctl is not None:
|
||||
sysctl_with_str_values = {k: str(v) for k, v in aparam_sysctl.items()}
|
||||
if sysctl_with_str_values != lb_facts['sysctlParams']:
|
||||
self.lb_update_sysctl(
|
||||
lb_id=lb_facts['id'],
|
||||
sysctl=aparam_sysctl,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def _lb_delete_backends(self,back_list,lb_fronts):
|
||||
@@ -6556,6 +6638,22 @@ class DecortController(object):
|
||||
|
||||
return
|
||||
|
||||
@waypoint
|
||||
@checkmode
|
||||
def lb_update_sysctl(self, lb_id: int, sysctl: dict):
|
||||
sysctl_with_str_values = json.dumps(
|
||||
{k: str(v) for k, v in sysctl.items()}
|
||||
)
|
||||
self.decort_api_call(
|
||||
arg_req_function=requests.post,
|
||||
arg_api_name='/restmachine/cloudapi/lb/updateSysctlParams',
|
||||
arg_params={
|
||||
'lbId': lb_id,
|
||||
'sysctlParams': sysctl_with_str_values,
|
||||
},
|
||||
)
|
||||
self.set_changed()
|
||||
|
||||
@waypoint
|
||||
@checkmode
|
||||
def snapshot_create(self, compute_id: int, label: str):
|
||||
|
||||
Reference in New Issue
Block a user