Fixing initial bugs in Disk and KvmVM modules, adjusting utility module accordingly

master
Sergey Shubin svs1370 5 years ago
parent 125ebb1fb8
commit e5edf40b6e

@ -78,20 +78,20 @@ options:
- URL of the DECORT controller that will be contacted to manage the RG according to the specification. - URL of the DECORT controller that will be contacted to manage the RG according to the specification.
- 'This parameter is always required regardless of the specified I(authenticator) type.' - 'This parameter is always required regardless of the specified I(authenticator) type.'
required: yes required: yes
disk_id: id:
description: description:
- `ID of the disk to manage. If I(disk_id) is specified it is assumed, that this disk already - `ID of the disk to manage. If I(id) is specified it is assumed, that this disk already
exists. In other words, you cannot create new disk by specifying its ID, use I(disk_name) exists. In other words, you cannot create new disk by specifying its ID, use I(name)
when creating new disk.` when creating new disk.`
- `If non-zero I(disk_id) is specified, then I(disk_name), I(account_id) and I(account_name) - `If non-zero I(id) is specified, then I(name), I(account_id) and I(account_name)
are ignored.` are ignored.`
default: 0 default: 0
required: no required: no
disk_name: name:
description: description:
- `Name of the disk to manage. To manage disk by name you also need to specify either - `Name of the disk to manage. To manage disk by name you also need to specify either
I(account_id) or I(account_name).` I(account_id) or I(account_name).`
- If non-zero I(disk_id) is specified, I(disk_name) is ignored. - If non-zero I(id) is specified, I(name) is ignored.
- `Note that the platform does not enforce uniqueness of disk names, so if more than one - `Note that the platform does not enforce uniqueness of disk names, so if more than one
disk with this name exists under the specified account, module will return the first disk with this name exists under the specified account, module will return the first
occurence.` occurence.`
@ -206,7 +206,7 @@ EXAMPLES = '''
app_id: "{{ MY_APP_ID }}" app_id: "{{ MY_APP_ID }}"
app_secret: "{{ MY_APP_SECRET }}" app_secret: "{{ MY_APP_SECRET }}"
controller_url: "https://cloud.digitalenergy.online" controller_url: "https://cloud.digitalenergy.online"
disk_name: "MyDataDisk01" name: "MyDataDisk01"
sep_id: 1 sep_id: 1
pool: "default" pool: "default"
size: 50 size: 50
@ -288,7 +288,7 @@ def decort_disk_parameters():
return dict( return dict(
account_id=dict(type='int', required=False, default=0), account_id=dict(type='int', required=False, default=0),
account_name=dict(type='str', required=False, default=''), account_name=dict(type='str', required=False, default=''),
annotation=dict(type='str', required=False, default=''), annotation=dict(type='str', required=False, default='Disk by decort_disk'),
app_id=dict(type='str', app_id=dict(type='str',
required=False, required=False,
fallback=(env_fallback, ['DECORT_APP_ID'])), fallback=(env_fallback, ['DECORT_APP_ID'])),
@ -300,8 +300,8 @@ def decort_disk_parameters():
required=True, required=True,
choices=['legacy', 'oauth2', 'jwt']), choices=['legacy', 'oauth2', 'jwt']),
controller_url=dict(type='str', required=True), controller_url=dict(type='str', required=True),
disk_id=dict(type='int', required=False, default=0), id=dict(type='int', required=False, default=0),
disk_name=dict(type='str', required=False), name=dict(type='str', required=False),
force_detach=dict(type='bool', required=False, default=False), force_detach=dict(type='bool', required=False, default=False),
jwt=dict(type='str', jwt=dict(type='str',
required=False, required=False,
@ -352,18 +352,18 @@ def main():
validated_acc_id = 0 validated_acc_id = 0
acc_facts = None # will hold Account facts acc_facts = None # will hold Account facts
if amodule.params['disk_id']: if amodule.params['id']:
# expect existing Disk with the specified ID # expect existing Disk with the specified ID
# This call to disk_find will abort the module if no Disk with such ID is present # This call to disk_find will abort the module if no Disk with such ID is present
disk_id, disk_facts = decon.disk_find(amodule.params['disk_id']) disk_id, disk_facts = decon.disk_find(amodule.params['id'])
if not disk_id: if not disk_id:
decon.result['failed'] = True decon.result['failed'] = True
decon.result['msg'] = "Specified Disk ID {} not found.".format(amodule.params['disk_id']) decon.result['msg'] = "Specified Disk ID {} not found.".format(amodule.params['id'])
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
validated_acc_id =disk_facts['accountId'] validated_acc_id =disk_facts['accountId']
elif (amodule.params['account_id'] or amodule.params['account_name'] != "") and amodule.params['disk_name'] != "": elif (amodule.params['account_id'] or amodule.params['account_name'] != "") and amodule.params['name'] != "":
# Make sure disk name is specified, if not - fail the module # Make sure disk name is specified, if not - fail the module
if amodule.params['disk_name'] == "": if amodule.params['name'] == "":
decon.result['failed'] = True decon.result['failed'] = True
decon.result['msg'] = ("Cannot manage disk if both ID is 0 and disk name is empty.") decon.result['msg'] = ("Cannot manage disk if both ID is 0 and disk name is empty.")
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
@ -375,7 +375,7 @@ def main():
"or non-existent account specified.") "or non-existent account specified.")
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
# This call to disk_find may return disk_id=0 if no Disk with this name found in # This call to disk_find may return disk_id=0 if no Disk with this name found in
disk_id, disk_facts = decon.disk_find(disk_id=0, disk_name=amodule.params['disk_name'], disk_id, disk_facts = decon.disk_find(disk_id=0, disk_name=amodule.params['name'],
account_id=validated_acc_id, account_id=validated_acc_id,
check_state=False) check_state=False)
else: else:
@ -384,7 +384,7 @@ def main():
decon.result['failed'] = True decon.result['failed'] = True
if amodule.params['account_id'] == 0 and amodule.params['account_name'] == "": if amodule.params['account_id'] == 0 and amodule.params['account_name'] == "":
decon.result['msg'] = "Cannot find Disk by name when account name is empty and account ID is 0." decon.result['msg'] = "Cannot find Disk by name when account name is empty and account ID is 0."
if amodule.params['disk_name'] == "": if amodule.params['name'] == "":
decon.result['msg'] = "Cannot find Disk by empty name." decon.result['msg'] = "Cannot find Disk by empty name."
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
@ -400,6 +400,8 @@ def main():
# #
disk_should_exist = False disk_should_exist = False
target_sep_id = 0
target_pool = "default"
if disk_id: if disk_id:
disk_should_exist = True disk_should_exist = True
@ -451,8 +453,8 @@ def main():
elif decon.check_amodule_argument('place_with', False) and amodule.params['place_with'] > 0: elif decon.check_amodule_argument('place_with', False) and amodule.params['place_with'] > 0:
# request to place this disk on the same SEP as the specified OS image # request to place this disk on the same SEP as the specified OS image
# validate specified OS image and assign SEP ID accordingly # validate specified OS image and assign SEP ID accordingly
image_id, image_facts = decon.image_find() image_id, image_facts = decon.image_find(amodule.params['place_with'], "", 0)
pass target_sep_id = image_facts['sepid']
else: else:
# no new SEP ID is explicitly specified, and no place_with option - use sep_id from the disk_facts # no new SEP ID is explicitly specified, and no place_with option - use sep_id from the disk_facts
target_sep_id = disk_facts['sepid'] target_sep_id = disk_facts['sepid']
@ -480,14 +482,29 @@ def main():
decon.result['failed'] = False decon.result['failed'] = False
decon.result['changed'] = False decon.result['changed'] = False
decon.result['msg'] = ("Nothing to do as target state 'absent' was requested for " decon.result['msg'] = ("Nothing to do as target state 'absent' was requested for "
"non-existent Disk name '{}'").format(amodule.params['disk_name']) "non-existent Disk name '{}'").format(amodule.params['name'])
elif amodule.params['state'] == 'present': elif amodule.params['state'] == 'present':
decon.check_amodule_argument('disk_name') decon.check_amodule_argument('name') # if disk name not specified, fail the module
# as we already have account ID, we can create Disk and get disk_id on success decon.check_amodule_argument('size') # if disk size not specified, fail the module
#
# TODO: implement SEP ID selction logic # as we already have account ID, we can create Disk and get disk id on success
# if decon.check_amodule_argument('sep_id', False) and amodule.params['sep_id'] > 0:
disk_id = decon.disk_provision(disk_name=disk_facts['name'], # as this disk was found, its name is in the facts # non-zero sep_id is explicitly passed in module arguments
target_sep_id = amodule.params['sep_id']
elif decon.check_amodule_argument('place_with', False) and amodule.params['place_with'] > 0:
# request to place this disk on the same SEP as the specified OS image
# validate specified OS image and assign SEP ID accordingly
image_id, image_facts = decon.image_find(amodule.params['place_with'], "", 0)
target_sep_id = image_facts['sepid']
else:
# no SEP ID is explicitly specified, and no place_with option - we do not know where
# to place the new disk - fail the module
decon.result['failed'] = True
decon.result['msg'] = ("Cannot create new Disk name '{}': no SEP ID specified and "
"no 'place_with' option used.").format(amodule.params['name'])
amodule.fail_json(**decon.result)
disk_id = decon.disk_provision(disk_name=amodule.params['name'],
size=amodule.params['size'], size=amodule.params['size'],
account_id=validated_acc_id, account_id=validated_acc_id,
sep_id=target_sep_id, sep_id=target_sep_id,
@ -500,7 +517,7 @@ def main():
decon.result['changed'] = False decon.result['changed'] = False
decon.result['msg'] = ("Invalid target state '{}' requested for non-existent " decon.result['msg'] = ("Invalid target state '{}' requested for non-existent "
"Disk name '{}'").format(amodule.params['state'], "Disk name '{}'").format(amodule.params['state'],
amodule.params['disk_name']) amodule.params['name'])
# #
# conditional switch end - complete module run # conditional switch end - complete module run

@ -105,6 +105,11 @@ options:
it accordingly. Note that resize operation on a running VM may generate errors as not all OS images support it accordingly. Note that resize operation on a running VM may generate errors as not all OS images support
hot resize feature.' hot resize feature.'
required: no required: no
data_disks:
description:
- Optional list of integer IDs of the pre-existing disks that will be attached to this VM.
- These are additional disks (aka data disks) besides boot disk, which is created and attached automatically.
required: no
id: id:
description: description:
- ID of the KVM VM to manage. - ID of the KVM VM to manage.
@ -542,7 +547,7 @@ class decort_kvmvm(DecortController):
# if we get through here, all parameters required to create new Compute instance should be at hand # if we get through here, all parameters required to create new Compute instance should be at hand
self.comp_id = self.compute_provision(rg_id=self.rg_id, self.comp_id = self.kvmvm_provision(rg_id=self.rg_id,
comp_name=self.amodule.params['name'], arch=self.amodule.params['arch'], comp_name=self.amodule.params['name'], arch=self.amodule.params['arch'],
cpu=self.amodule.params['cpu'], ram=self.amodule.params['ram'], cpu=self.amodule.params['cpu'], ram=self.amodule.params['ram'],
boot_disk=validated_bdisk_size, boot_disk=validated_bdisk_size,

@ -763,14 +763,16 @@ class DecortController(object):
api_params = dict(rgId=rg_id, api_params = dict(rgId=rg_id,
name=comp_name, name=comp_name,
description=annotation, cpu=cpu, ram=ram,
vcpus=cpu, memory=ram,
imageId=image_id, imageId=image_id,
disksize=boot_disk, bootDisk=boot_disk,
start_machine=start_on_create) # start_machine parameter requires DECORT API ver 3.3.1 or higher start=start_on_create) # start_machine parameter requires DECORT API ver 3.3.1 or higher
if userdata: if userdata:
api_params['userdata'] = json.dumps(userdata) # we need to pass a string object as "userdata" api_params['userdata'] = json.dumps(userdata) # we need to pass a string object as "userdata"
if annotation:
api_params['decs'] = annotation
api_resp = self.decort_api_call(requests.post, api_url, api_params) 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. # On success the above call will return here. On error it will abort execution by calling fail_json.
self.result['failed'] = False self.result['failed'] = False
@ -1149,7 +1151,7 @@ class DecortController(object):
self.result['failed'] = True self.result['failed'] = True
self.result['msg'] = ("Failed to find RG ID {}, and account ID is zero.").format(rg_id) self.result['msg'] = ("Failed to find RG ID {}, and account ID is zero.").format(rg_id)
return 0, None return 0, None
validated_acc_id = rg_facts['accountId'] validated_acc_id = rg_facts['accountId']
api_params = dict(accountId=validated_acc_id) api_params = dict(accountId=validated_acc_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/images/list", api_params) api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/images/list", api_params)
@ -2212,17 +2214,10 @@ class DecortController(object):
return 0, None return 0, None
elif disk_name != "": elif disk_name != "":
if account_id > 0: if account_id > 0:
# TODO: in the absense of disks/list or disks/search API call it is not possible to
# fully implement this method
#
self.result['failed'] = True
self.result['msg'] = "disk_find(): looking up disk by name and account ID not implemented."
self.amodule.fail_json(**self.result)
#
api_params = dict(accountId=account_id, api_params = dict(accountId=account_id,
name=disk_name, name=disk_name,
showAll=False) # we do not want to see disks in DESTROYED, PURGED or invalid states showAll=False) # we do not want to see disks in DESTROYED, PURGED or invalid states
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/search", api_params) api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/list", api_params)
# the above call may return more than one matching disk # the above call may return more than one matching disk
disks_list = json.loads(api_resp.content.decode('utf8')) disks_list = json.loads(api_resp.content.decode('utf8'))
for runner in disks_list: for runner in disks_list:
@ -2287,6 +2282,9 @@ class DecortController(object):
if api_resp.status_code == 200: if api_resp.status_code == 200:
ret_disk_id = json.loads(api_resp.content.decode('utf8')) ret_disk_id = json.loads(api_resp.content.decode('utf8'))
self.result['failed'] = False
self.result['changed'] = True
return ret_disk_id return ret_disk_id
def disk_resize(self, disk_facts, new_size): def disk_resize(self, disk_facts, new_size):

Loading…
Cancel
Save