Some impruvments and updates

rc-5.2.4
Alex_geth 2 years ago
parent b03b82e492
commit ae85826129

@ -9,4 +9,4 @@ Requirements:
* PyJWT 2.0.0 Python module or higher
* requests Python module
* netaddr Python module
* DECORT cloud platform version 3.5.0 or higher
* DECORT cloud platform version 3.8.6 or higher

@ -252,161 +252,127 @@ from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
class decort_disk(DecortController):
def __init__(self,amodule):
super(decort_disk, self).__init__(amodule)
self.validated_account_id = 0
self.validated_disk_id = 0
self.disk_facts = None # will hold Disk facts
self.acc_facts = None # will hold Account facts
def __init__(self,arg_amodule):
super(decort_disk, self).__init__(arg_amodule)
validated_acc_id = 0
validated_acc_info = None
validated_disk_id = 0
self.disk_id = 0
self.account_id = 0
validated_disk_facts = None
# limitIO check for exclusive parameters
if amodule.params['limitIO']:
limit = amodule.params['limitIO']
if limit['total_bytes_sec'] > 0 and limit['read_bytes_sec'] > 0 or \
limit['total_bytes_sec'] > 0 and limit['write_bytes_sec'] > 0:
self.result['failed'] = True
self.result['msg'] = ("total and read/write of bytes_sec cannot be set at the same time.")
amodule.fail_json(**self.result)
elif limit['total_iops_sec'] > 0 and limit['read_iops_sec'] > 0 or \
limit['total_iops_sec'] > 0 and limit['write_iops_sec'] > 0:
self.result['failed'] = True
self.result['msg'] = ("total and read/write of iops_sec cannot be set at the same time.")
amodule.fail_json(**self.result)
elif limit['total_bytes_sec_max'] > 0 and limit['read_bytes_sec_max'] > 0 or \
limit['total_bytes_sec_max'] > 0 and limit['write_bytes_sec_max'] > 0:
self.result['failed'] = True
self.result['msg'] = ("total and read/write of bytes_sec_max cannot be set at the same time.")
amodule.fail_json(**self.result)
elif limit['total_iops_sec_max'] > 0 and limit['read_iops_sec_max'] > 0 or \
limit['total_iops_sec_max'] > 0 and limit['write_iops_sec_max'] > 0:
self.result['failed'] = True
self.result['msg'] = ("total and read/write of iops_sec_max cannot be set at the same time.")
amodule.fail_json(**self.result)
if amodule.params['account_id']:
self.validated_account_id = amodule.params['account_id']
elif amodule.params['account_name']:
self.validated_account_id, _ = self.account_find(amodule.params['account_name'])
elif not amodule.params['id'] and not amodule.params['account_name']:
self.result['failed'] = True
self.result['msg'] = ("Cannot found disk without account id or name.")
amodule.fail_json(**self.result)
if self.validated_account_id == 0 and not amodule.params['id']:
# we failed either to find or access the specified account - fail the module
self.result['failed'] = True
self.result['msg'] = ("Cannot find account '{}'").format(amodule.params['account_name'])
amodule.fail_json(**self.result)
if arg_amodule.params['limitIO']:
self.disk_check_iotune_arg(arg_amodule.params['limitIO'])
if amodule.params['id'] or amodule.params['name']:
self.validated_disk_id, self.disk_facts = self.decort_disk_find(amodule)
if arg_amodule.params['id'] or arg_amodule.params['name']:
if arg_amodule.params['account_id'] or arg_amodule.params['account_name'] :
validated_acc_id,validated_acc_info = self.account_find(arg_amodule.params['account_name'],arg_amodule.params['account_id'])
if not validated_acc_id:
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = ("Current user does not have access to the account ID {} / "
"name '{}' or non-existent account specified.").format(arg_amodule.params['account_id'],
arg_amodule.params['account_name'])
self.fail_json(**self.result)
else:
self.acc_id = validated_acc_id
self.acc_info = validated_acc_info
validated_disk_id,validated_disk_facts = self.disk_find(
disk_id=arg_amodule.params['id'],
name=arg_amodule.params['name'] if "name" in arg_amodule.params else "",
account_id=self.acc_id,
check_state=False,
)
else:
self.result['failed'] = True
self.result['msg'] = ("Cannot find or create disk without disk name or disk id")
amodule.fail_json(**self.result)
if amodule.params['place_with'] > 0:
image_id, image_facts = self.image_find(amodule.params['place_with'], "", 0)
amodule.params['sep_id']= image_facts['sepId']
def decort_disk_create(self, amodule):
if not self.disk_facts:
self.disk_id = self.disk_create(accountId=self.validated_account_id, gid=amodule.params['gid'],
name=amodule.params['name'], description=amodule.params['description'],
size=amodule.params['size'], type=amodule.params['type'],
iops=amodule.params['iops'],
sep_id=amodule.params['sep_id'], pool=amodule.params['pool'])
self.result['msg'] = ("Disk with id '{}' successfully created.").format(self.disk_id)
elif self.disk_facts['status'] in ["DESTROYED", "PURGED"]:
if not amodule.params['limitIO']:
amodule.params['limitIO'] = self.disk_facts['iotune']
if amodule.params['sep_id'] == 0:
validated_sep_id = self.disk_facts['sepId']
else:
validated_sep_id = amodule.params['sep_id']
self.result['msg'] = ("Cannot manage Disk when its ID is 0 and name is empty")
self.fail_json(**self.result)
if arg_amodule.params['place_with']:
image_id, image_facts = self.image_find(arg_amodule.params['place_with'], "", 0)
arg_amodule.params['sep_id'] = image_facts['sepId']
self.disk_id = validated_disk_id
self.disk_info = validated_disk_facts
def create(self):
self.disk_id = self.disk_create(accountId=self.acc_id,
name = self.amodule.params['name'],
description=self.amodule.params['annotation'],
size=self.amodule.params['size'],
type=self.amodule.params['type'],
iops=self.amodule.params['iops'],
sep_id=self.amodule.params['sep_id'],
pool=self.amodule.params['pool'],
)
#IO tune
if self.amodule.params['limitIO']:
self.disk_limitIO(self.amodule.params['limitIO'],self.disk_id)
#set share status
if self.amodule.params['shareable'] and self.amodule.params['type'] == "D":
self.dick_share(self.disk_id,self.amodule.params['shareable'])
return
if amodule.params['pool'] == 0:
validated_pool = self.disk_facts['pool']
else:
validated_pool = amodule.params['pool']
def action(self,restore=False):
#restore never be done
if restore:
self.disk_restore(self.disk_id)
#rename if id present
if self.amodule.params['name'] != self.disk_info['name']:
self.disk_rename(diskId=self.disk_id,
name=self.amodule.params['name'])
self.disk_info['name'] = self.amodule.params['name']
#resize
if self.amodule.params['size'] != self.disk_info['sizeMax']:
self.disk_resize(self.disk_info,self.amodule.params['size'])
#IO TUNE
if self.amodule.params['limitIO']:
clean_io = [param for param in self.amodule.params['limitIO'] \
if self.amodule.params['limitIO'][param] == None]
for key in clean_io: del self.amodule.params['limitIO'][key]
if self.amodule.params['limitIO'] != self.disk_info['iotune']:
self.disk_limitIO(self.disk_id,self.amodule.params['limitIO'])
#share check/update
#raise Exception(self.amodule.params['shareable'])
if self.amodule.params['shareable'] != self.disk_info['shareable'] and \
self.amodule.params['type'] == "D":
self.disk_share(self.disk_id,self.amodule.params['shareable'])
return
if amodule.params['size'] == 0:
validated_size = self.disk_facts['sizeMax']
else:
validated_size = amodule.params['size']
def delete(self):
self.disk_id = self.disk_delete(disk_id=self.disk_id,
detach=self.amodule.params['force_detach'],
permanently=self.amodule.params['permanently'],
reason=self.amodule.params['reason'])
self.disk_info['status'] = "DELETED"
return
if amodule.params['gid'] == 0:
validated_gid = self.disk_facts['gid']
else:
validated_gid = amodule.params['gid']
def rename(self):
self.disk_id = self.disk_create(accountId=self.validated_account_id, gid=validated_gid,
name=self.disk_facts['name'], description=amodule.params['description'],
size=validated_size, type=self.disk_facts['type'],
iops=self.disk_facts['iotune']['total_iops_sec'],
sep_id=validated_sep_id, pool=validated_pool)
if not amodule.params['limitIO']:
amodule.params['limitIO'] = self.disk_facts['iotune']
self.result['msg'] = ("Disk with id '{}' successfully recreated.").format(self.disk_id)
self.result['failed'] = False
self.result['changed'] = True
return self.disk_id
def decort_disk_delete(self, amodule):
self.disk_id = self.disk_delete(disk_id=self.validated_disk_id,
detach=amodule.params['force_detach'],
permanently=amodule.params['permanently'],
reason=amodule.params['reason'])
self.disk_rename(diskId = self.disk_id,
name = self.amodule.params['name'])
self.disk_info['name'] = self.amodule.params['name']
return
def nop(self):
def decort_disk_find(self, amodule):
if amodule.params['name'] and not amodule.params['id']:
self.disk_id, self.disk_facts = self.disk_find(disk_id=self.validated_disk_id,
name=amodule.params['name'],
account_id=self.validated_account_id)
elif self.validated_disk_id > 0:
self.disk_id, self.disk_facts = self.disk_find(disk_id=self.validated_disk_id,
name=self.disk_facts['name'],
account_id=0)
elif amodule.params['id']:
self.disk_id, self.disk_facts = self.disk_find(disk_id=amodule.params['id'],
name=amodule.params['name'],
account_id=0)
if not self.disk_id and not amodule.params['name']:
self.result['failed'] = True
self.result['msg'] = "Specified Disk ID {} not found.".format(amodule.params['id'])
amodule.fail_json(**self.result)
self.result['facts'] = decort_disk.decort_disk_package_facts(self.disk_facts)
return self.disk_id, self.disk_facts
def decort_disk_limitIO(self, amodule):
self.limits = amodule.params['limitIO']
self.disk_limitIO(limits = self.limits,
diskId = self.validated_disk_id)
self.disk_facts['iotune'] = amodule.params['limitIO']
self.result['facts'] = decort_disk.decort_disk_package_facts(self.disk_facts)
return
def decort_disk_rename(self, amodule):
self.disk_rename(diskId = self.validated_disk_id,
name = amodule.params['name'])
self.disk_facts['name'] = amodule.params['name']
self.result['facts'] = decort_disk.decort_disk_package_facts(self.disk_facts)
self.result['msg'] = ("Disk with id '{}',successfully renamed to '{}'.").format(self.validated_disk_id, amodule.params['name'])
self.result['failed'] = False
self.result['changed'] = False
if self.disk_id:
self.result['msg'] = ("No state change required for Disk ID {} because of its "
"current status '{}'.").format(self.disk_id, self.disk_info['status'])
else:
self.result['msg'] = ("No state change to '{}' can be done for "
"non-existent Disk.").format(self.amodule.params['state'])
return
def decort_disk_package_facts(disk_facts, check_mode=False):
def package_facts(self, check_mode=False):
ret_dict = dict(id=0,
name="none",
state="CHECK_MODE",
@ -418,29 +384,27 @@ class decort_disk(DecortController):
gid=0
)
if check_mode:
# in check mode return immediately with the default values
if check_mode or self.disk_info is None:
return ret_dict
if disk_facts is None:
# if void facts provided - change state value to ABSENT and return
ret_dict['state'] = "ABSENT"
return ret_dict
ret_dict['id'] = disk_facts['id']
ret_dict['name'] = disk_facts['name']
ret_dict['size'] = disk_facts['sizeMax']
ret_dict['state'] = disk_facts['status']
ret_dict['account_id'] = disk_facts['accountId']
ret_dict['sep_id'] = disk_facts['sepId']
ret_dict['pool'] = disk_facts['pool']
ret_dict['attached_to'] = disk_facts['vmid']
ret_dict['gid'] = disk_facts['gid']
ret_dict['iotune'] = disk_facts['iotune']
# remove io param with zero value
clean_io = [param for param in self.disk_info['iotune'] if self.disk_info['iotune'][param] == 0]
for key in clean_io: del self.disk_info['iotune'][key]
ret_dict['id'] = self.disk_info['id']
ret_dict['name'] = self.disk_info['name']
ret_dict['size'] = self.disk_info['sizeMax']
ret_dict['state'] = self.disk_info['status']
ret_dict['account_id'] = self.disk_info['accountId']
ret_dict['sep_id'] = self.disk_info['sepId']
ret_dict['pool'] = self.disk_info['pool']
ret_dict['attached_to'] = self.disk_info['vmid']
ret_dict['gid'] = self.disk_info['gid']
ret_dict['iotune'] = self.disk_info['iotune']
return ret_dict
def decort_disk_parameters():
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_disk module in a form accepted
by AnsibleModule utility class."""
@ -476,32 +440,30 @@ class decort_disk(DecortController):
place_with=dict(type='int', default=0),
pool=dict(type='str', default=''),
sep_id=dict(type='int', default=0),
gid=dict(type='int', default=0),
size=dict(type='int', default=0),
type=dict(type='str',
required=False,
default="D",
choices=['B', 'D', 'T']),
iops=dict(type='int', default=2000),
iops=dict(type='int',required=False,default=2000),
limitIO=dict(type='dict',
options=dict(
total_bytes_sec=dict(default=0,type='int'),
read_bytes_sec=dict(default=0,type='int'),
write_bytes_sec=dict(default=0,type='int'),
total_iops_sec=dict(default=0,type='int'),
read_iops_sec=dict(default=0,type='int'),
write_iops_sec=dict(default=0,type='int'),
total_bytes_sec_max=dict(default=0,type='int'),
read_bytes_sec_max=dict(default=0,type='int'),
write_bytes_sec_max=dict(default=0,type='int'),
total_iops_sec_max=dict(default=0,type='int'),
read_iops_sec_max=dict(default=0,type='int'),
write_iops_sec_max=dict(default=0,type='int'),
size_iops_sec=dict(default=0,type='int'),)),
total_bytes_sec=dict(required=False,type='int'),
read_bytes_sec=dict(required=False,type='int'),
write_bytes_sec=dict(required=False,type='int'),
total_iops_sec=dict(required=False,type='int'),
read_iops_sec=dict(required=False,type='int'),
write_iops_sec=dict(required=False,type='int'),
total_bytes_sec_max=dict(required=False,type='int'),
read_bytes_sec_max=dict(required=False,type='int'),
write_bytes_sec_max=dict(required=False,type='int'),
total_iops_sec_max=dict(required=False,type='int'),
read_iops_sec_max=dict(required=False,type='int'),
write_iops_sec_max=dict(required=False,type='int'),
size_iops_sec=dict(required=False,type='int'),)),
permanently=dict(type='bool', required=False, default=False),
reason=dict(type='int', required=False),
description=dict(type='str', required=False,
default="Disk created with Ansible Decort_disk module."),
shareable=dict(type='bool', required=False, default=False),
reason=dict(type='str', required=False,default='Managed by Ansible decort_disk'),
state=dict(type='str',
default='present',
choices=['absent', 'present']),
@ -514,7 +476,7 @@ class decort_disk(DecortController):
)
def main():
module_parameters = decort_disk.decort_disk_parameters()
module_parameters = decort_disk.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
@ -530,105 +492,51 @@ def main():
)
decon = decort_disk(amodule)
if decon.validated_disk_id == 0 and amodule.params['state'] == 'present':
# if sep_id or place_with not specified, then exit with error
if amodule.params['sep_id'] == 0 and amodule.params['place_with'] == 0:
decon.result['msg'] = ("To create a disk, you must specify sep_id or place_with.")\
.format(decon.validated_disk_id)
amodule.fail_json(**decon.result)
# if id cannot cannot be found and have a state 'present', then create a new disk
decon.validated_disk_id = decon.decort_disk_create(amodule)
_, decon.disk_facts = decon.decort_disk_find(amodule)
decon.result['changed'] = True
decon.result['msg'] = ("Disk with id '{}' successfully created.").format(decon.validated_disk_id)
elif decon.validated_disk_id == 0 and amodule.params['state'] == 'absent' and amodule.params['name']:
# if disk with specified name cannot be found and have a state 'absent', then nothing to do,
# specified disk already deleted
decon.result['msg'] = ("Disk with name '{}' has already been deleted or your account does not have"
" access to it.")\
.format(amodule.params['name'])
amodule.exit_json(**decon.result)
elif decon.validated_disk_id == 0 and amodule.params['state'] == 'absent' and amodule.params['id']:
# if disk with specified id cannot be found and have a state 'absent', then nothing to do,
# specified disk already deleted
decon.result['msg'] = ("Disk with name '{}' has already been deleted or your account does not have"
" access to it.")\
.format(decon.validated_disk_id)
amodule.exit_json(**decon.result)
elif decon.disk_facts['status'] == "CREATED":
if amodule.params['state'] == 'present':
# if disk status in condition "CREATED" and state "present", nothing to do,
# specified disk already created
decon.result['msg'] = "Specified Disk ID {} already created.".format(decon.validated_disk_id)
#
#Full range of Disk status is as follows:
#
# "ASSIGNED","MODELED", "CREATING","CREATED","DELETED", "DESTROYED","PURGED",
#
if decon.disk_id:
#disk exist
if decon.disk_info['status'] in ["MODELED", "CREATING"]:
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("No change can be done for existing Disk ID {} because of its current "
"status '{}'").format(decon.disk_id, decon.disk_info['status'])
# "ASSIGNED","CREATED","DELETED","PURGED", "DESTROYED"
elif decon.disk_info['status'] in ["ASSIGNED","CREATED"]:
if amodule.params['state'] == 'absent':
decon.delete()
elif amodule.params['state'] == 'present':
decon.action()
elif decon.disk_info['status'] in ["PURGED", "DESTROYED"]:
#re-provision disk
if amodule.params['state'] in ('present'):
decon.create()
else:
decon.nop()
elif decon.disk_info['status'] == "DELETED":
if amodule.params['state'] in ('present'):
decon.action(restore=True)
else:
decon.nop()
else:
# preexisting Disk was not found
if amodule.params['state'] == 'absent':
# if disk status in condition "CREATED" and state "absent", delete the disk
decon.validated_disk_id = decon.decort_disk_delete(amodule)
decon.disk_facts['status'] = "DESTROYED"
decon.result['msg'] = ("Disk with id '{}' successfully deleted.").format(decon.disk_facts['id'])
decon.result['facts'] = decon.decort_disk_package_facts(decon.disk_facts)
amodule.exit_json(**decon.result)
elif decon.disk_facts['status'] in ["MODELED", "CREATING" ]:
# if disk in status "MODELED" or "CREATING",
# then we cannot do anything, while disk in this status
decon.result['changed'] = False
decon.result['msg'] = ("Cannot do anything with disk id '{}',please wait until disk will be created.")\
.format(decon.validated_disk_id)
amodule.fail_json(**decon.result)
decon.nop()
else:
decon.create()
elif decon.disk_facts['status'] == "DELETED":
if amodule.params['state'] == 'present':
# if disk in "DELETED" status and "present" state, restore
decon.disk_restore(decon.validated_disk_id)
_, decon.disk_facts = decon.decort_disk_find(amodule)
decon.result['changed'] = True
decon.result['msg'] = ("Disk with id '{}',restored successfully.").format(decon.validated_disk_id)
elif amodule.params['state'] == 'absent':
# if disk in "DELETED" status and "absent" state, nothing to do
decon.result['msg'] = "Specified Disk ID {} already destroyed.".format(decon.validated_disk_id)
amodule.exit_json(**decon.result)
elif decon.disk_facts['status'] in ["DESTROYED", "PURGED"]:
if amodule.params['state'] == 'present':
decon.validated_disk_id = decon.decort_disk_create(amodule)
_, decon.disk_facts = decon.decort_disk_find(amodule)
elif amodule.params['state'] == 'absent':
decon.result['msg'] = "Specified Disk ID {} already destroyed.".format(decon.validated_disk_id)
amodule.exit_json(**decon.result)
if amodule.params['state'] == "present":
if decon.disk_facts['sizeMax'] != amodule.params['size']:
if decon.disk_facts['sizeMax'] > amodule.params['size'] and amodule.params['size'] != 0:
decon.result['failed'] = True
decon.result['msg'] = ("Disk id '{}', cannot reduce disk size.").format(decon.validated_disk_id)
amodule.fail_json(**decon.result)
elif decon.disk_facts['sizeMax'] < amodule.params['size']:
decon.disk_resize(disk_facts=decon.disk_facts,
new_size=amodule.params['size'])
decon.result['changed'] = True
decon.disk_facts['size'] = amodule.params['size']
decon.result['msg'] = ("Disk with id '{}',resized successfully.").format(decon.validated_disk_id)
if amodule.params['limitIO'] and amodule.params['limitIO'] != decon.disk_facts['iotune']:
decon.decort_disk_limitIO(amodule)
decon.result['changed'] = True
decon.result['msg'] = ("Disk with id '{}',limited successfully.").format(decon.validated_disk_id)
if amodule.params['name'] and amodule.params['id']:
if amodule.params['name'] != decon.disk_facts['name']:
decon.decort_disk_rename(amodule)
decon.result['changed'] = True
decon.result['msg'] = ("Disk with id '{}',renamed successfully from '{}' to '{}'.")\
.format(decon.validated_disk_id, decon.disk_facts['name'], amodule.params['name'])
amodule.exit_json(**decon.result)
if decon.result['failed']:
amodule.fail_json(**decon.result)
else:
if decon.result['changed'] and amodule.params['state'] in ('present'):
_, decon.disk_info = decon.disk_find(decon.disk_id)
decon.result['facts'] = decon.package_facts(amodule.check_mode)
amodule.exit_json(**decon.result)
if __name__ == "__main__":
main()
#SHARE

@ -1,19 +1,68 @@
#!/usr/bin/python
#
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
# Copyright: (c) 2018-2021 Digital Energy Cloud Solutions LLC
# Copyright: (c) 2018-2023 Digital Energy Cloud Solutions LLC
#
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#
#
# Author: Aleksandr Malyavin (aleksandr.malyavin@digitalenergy.online)
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
---
'''
EXAMPLES = '''
- name: Create k8s cluster
decort_k8s:
verify_ssl: false
authenticator: jwt
jwt: "{{ run_jwt.jwt }}"
controller_url: "{{CONTROLLER_URL}}"
name: SOME_NAME
rg_id: {{RG_ID}}
k8ci_id: 10
master_count: 3
master_cpu: 2
master_ram: 2048
master_disk: 10
state: present
permanent: True
started: True
getConfig: True
network_plugin: flannel
workers:
- name: wg1
ram: 1024
cpu: 2
disk: 10
num: 1
labels:
- disktype1=ssd1
- disktype2=ssd2
- disktype3=ssd3
taints:
- key1=value1:NoSchedule
- key2=value2:NoSchedule
- key3=value3:NoSchedule
annotations:
- node.deckhouse.io/group1=g1
- node.deckhouse.io/group2=g2
- node.deckhouse.io/group3=g3
- name: wg2
ram: 1024
cpu: 2
disk: 10
num: 1
labels:
- apptype=main
annotations:
- node.mainapp.domen.local/group1=g1
register: some_cluster
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
@ -26,6 +75,12 @@ class decort_k8s(DecortController):
validated_rg_id = 0
validated_rg_facts = None
validated_k8ci_id = 0
self.k8s_should_exist = False
if not arg_amodule.params['workers']:
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = "At least one worker group must be present"
self.fail_json(**self.result)
if arg_amodule.params['name'] == "" and arg_amodule.params['id'] == 0:
self.result['failed'] = True
@ -108,9 +163,11 @@ class decort_k8s(DecortController):
ret_dict['techStatus'] = self.k8s_info['techStatus']
ret_dict['state'] = self.k8s_info['status']
ret_dict['rg_id'] = self.rg_id
ret_dict['vins_id'] = self.k8s_vins_id
ret_dict['account_id'] = self.acc_id
if self.amodule.params['getConfig'] and self.k8s_info['techStatus'] == "STARTED":
ret_dict['config'] = self.k8s_getConfig()
return ret_dict
def nop(self):
@ -149,10 +206,11 @@ class decort_k8s(DecortController):
self.k8s_provision(self.amodule.params['name'],
self.amodule.params['k8ci_id'],
self.amodule.params['rg_id'],
self.amodule.params['network_plugin'],
self.amodule.params['master_count'],
self.amodule.params['master_cpu'],
self.amodule.params['master_ram_mb'],
self.amodule.params['master_disk_gb'],
self.amodule.params['master_ram'],
self.amodule.params['master_disk'],
self.amodule.params['workers'][0],
self.amodule.params['extnet_id'],
self.amodule.params['with_lb'],
@ -165,12 +223,12 @@ class decort_k8s(DecortController):
if self.k8s_id:
self.k8s_should_exist = True
if self.k8s_id and self.amodule.params['workers'][1]:
if self.k8s_id and len(self.amodule.params['workers'])>1 :
self.k8s_workers_modify(self.k8s_info,self.amodule.params['workers'])
return
def destroy(self):
self.k8s_delete(self.k8s_id)
self.k8s_delete(self.k8s_id,self.amodule.params['permanent'])
self.k8s_info['status'] = 'DELETED'
self.k8s_should_exist = False
return
@ -232,16 +290,17 @@ class decort_k8s(DecortController):
rg_id=dict(type='int', default=0),
rg_name=dict(type='str',default=""),
k8ci_id=dict(type='int', required=True),
network_plugin=dict(type='str',required=False,default="flannel"),
wg_name=dict(type='str', required=False),
master_count=dict(type='int', default=1),
master_cpu=dict(type='int', default=2),
master_ram_mb=dict(type='int', default=2048),
master_disk_gb=dict(type='int', default=10),
master_ram=dict(type='int', default=2048),
master_disk=dict(type='int', default=10),
worker_count=dict(type='int', default=1),
worker_cpu=dict(type='int', default=1),
worker_ram_mb=dict(type='int', default=1024),
worker_disk_gb=dict(type='int', default=10),
workers=dict(type='list'),
workers=dict(type='list',required=True),
extnet_id=dict(type='int', default=0),
description=dict(type='str', default="Created by decort ansible module"),
with_lb=dict(type='bool', default=True),

@ -1,15 +1,11 @@
#!/usr/bin/python
#
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
# Copyright: (c) 2018-2021 Digital Energy Cloud Solutions LLC
# Copyright: (c) 2018-2023 Digital Energy Cloud Solutions LLC
#
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#
#
# Author: Sergey Shubin (sergey.shubin@digitalenergy.online)
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
@ -24,15 +20,14 @@ description: >
network port forwarding rules, restart guest OS and delete a virtual machine thus releasing
corresponding cloud resources.
version_added: "2.2"
author:
- Sergey Shubin <sergey.shubin@digitalenergy.online>
requirements:
- python >= 2.6
- python >= 3.8
- PyJWT Python module
- requests Python module
- netaddr Python module
- decort_utils utility library (module)
- DECORT cloud platform version 3.6.1 or higher
- DECORT cloud platform version 3.8.6 or higher
notes:
- Environment variables can be used to pass selected parameters to the module, see details below.
- Specified Oauth2 provider must be trusted by the DECORT cloud controller on which JWT will be used.
@ -231,7 +226,7 @@ options:
choices: [ present, absent, poweredon, poweredoff, halted, paused, check ]
tags:
description:
- String of custom tags to be assigned to the VM (This feature is not implemented yet!).
- Dict of custom tags to be assigned to the VM.
- These tags are arbitrary text that can be used for grouping or indexing the VMs by other applications.
required: no
user:
@ -287,24 +282,14 @@ EXAMPLES = '''
name: SimpleVM
cpu: 2
ram: 4096
boot_disk:
size: 10
model: ovs
pool: boot
boot_disk: 10
image_name: "Ubuntu 16.04 v1.1"
data_disks:
- size: 50
model: ovs
pool: data
port_forwards:
- ext_port: 21022
int_port: 22
proto: tcp
- ext_port: 80
int_port: 80
proto: tcp
- {{DISK_ID}}
state: present
tags: "PROJECT:Ansible STATUS:Test"
tags:
PROJECT:Ansible
STATUS:Test
account_name: "Development"
rg_name: "ANewVDC"
delegate_to: localhost
@ -337,18 +322,6 @@ EXAMPLES = '''
state: poweredoff
delegate_to: localhost
register: simple_vm
- name: check if VM exists and read in its specs.
decort_kvmvm:
authenticator: oauth2
app_id: "{{ MY_APP_ID }}"
app_secret: "{{ MY_APP_SECRET }}"
controller_url: "https://ds1.digitalenergy.online"
name: "{{ TARGET_VM_NAME }}"
rg_name: "{{ TARGET_VDC_NAME }}"
account_name: "{{ TRAGET_TENANT }}"
state: check
delegate_to: localhost
register: existing_vm
'''
RETURN = '''
@ -573,6 +546,8 @@ class decort_kvmvm(DecortController):
image_id=image_facts['id'],
annotation=self.amodule.params['annotation'],
userdata=cloud_init_params,
sep_id=self.amodule.params['sep_id' ] if "sep_id" in self.amodule.params else None,
pool_name=self.amodule.params['pool'] if "pool" in self.amodule.params else None,
start_on_create=start_compute)
self.comp_should_exist = True
@ -652,11 +627,13 @@ class decort_kvmvm(DecortController):
self.compute_resize(self.comp_info,
self.amodule.params['cpu'], self.amodule.params['ram'],
wait_for_state_change=arg_wait_cycles)
self.compute_affinity(self.comp_info,
self.amodule.params['tag'],
self.amodule.params['aff_rule'],
self.amodule.params['aaff_rule'],
label=self.amodule.params['affinity_label'],)
return
def package_facts(self, check_mode=False):
@ -686,6 +663,7 @@ class decort_kvmvm(DecortController):
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={},
)
if check_mode or self.comp_info is None:
@ -703,6 +681,8 @@ class decort_kvmvm(DecortController):
ret_dict['tech_status'] = self.comp_info['techStatus']
ret_dict['account_id'] = self.comp_info['accountId']
ret_dict['rg_id'] = self.comp_info['rgId']
if self.comp_info['tags']:
ret_dict['tags'] = self.comp_info['tags']
# if the VM is an imported VM, then the 'accounts' list may be empty,
# so check for this case before trying to access login and passowrd values
if len(self.comp_info['osUsers']):
@ -764,6 +744,8 @@ class decort_kvmvm(DecortController):
required=True,
choices=['legacy', 'oauth2', 'jwt']),
boot_disk=dict(type='int', required=False),
sep_id=dict(type='int', required=False),
pool=dict(type='str', required=False),
controller_url=dict(type='str', required=True),
# count=dict(type='int', required=False, default=1),
cpu=dict(type='int', required=False),
@ -790,7 +772,7 @@ class decort_kvmvm(DecortController):
rg_name=dict(type='str', default=""),
ssh_key=dict(type='str', required=False),
ssh_key_user=dict(type='str', required=False),
tag=dict(type='list', required=False),
tag=dict(type='dict', required=False),
affinity_label=dict(type='str', required=False),
aff_rule=dict(type='list', required=False),
aaff_rule=dict(type='list', required=False),

@ -1,7 +1,7 @@
#!/usr/bin/python
#
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
# Copyright: (c) 2018-2022 Digital Energy Cloud Solutions LLC
# Copyright: (c) 2018-2023 Digital Energy Cloud Solutions LLC
#
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#

@ -388,6 +388,8 @@ class decort_rg(DecortController):
ret_dict['resTypes'] = self.rg_facts['resourceTypes']
ret_dict['defNetId'] = self.rg_facts['def_net_id']
ret_dict['defNetType'] = self.rg_facts['def_net_type']
ret_dict['ViNS'] = self.rg_facts['vins']
ret_dict['computes'] = self.rg_facts['vms']
return ret_dict

@ -6,9 +6,6 @@
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#
#
# Author: Sergey Shubin (sergey.shubin@digitalenergy.online)
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
@ -23,14 +20,13 @@ description: >
modify its characteristics, and delete it.
version_added: "2.2"
author:
- Sergey Shubin <sergey.shubin@digitalenergy.online>
requirements:
- python >= 2.6
- python >= 3.8
- PyJWT Python module
- requests Python module
- netaddr Python module
- decort_utils utility library (module)
- DECORT cloud platform version 3.6.1 or higher
- DECORT cloud platform version 3.8.6 or higher
notes:
- Environment variables can be used to pass selected parameters to the module, see details below.
- Specified Oauth2 provider must be trusted by the DECORT cloud controller on which JWT will be used.
@ -260,14 +256,15 @@ class decort_vins(DecortController):
if arg_amodule.params['vins_id']:
# expect existing ViNS with the specified ID
# This call to vins_find will abort the module if no ViNS with such ID is present
self.vins_id, self.vins_facts = self.vins_find(arg_amodule.params['vins_id'])
if not self.vins_id:
self.vins_id, self.vins_facts = self.vins_find(arg_amodule.params['vins_id'],check_state=False)
if self.vins_id == 0:
self.result['failed'] = True
self.result['msg'] = "Specified ViNS ID {} not found.".format(arg_amodule.params['vins_id'])
self.fail_json(**self.result)
self.vins_level = "ID"
validated_acc_id = vins_facts['accountId']
validated_rg_id = vins_facts['rgId']
#raise Exception(self.vins_facts)
validated_acc_id = self.vins_facts['accountId']
validated_rg_id = self.vins_facts['rgId']
elif arg_amodule.params['rg_id']:
# expect ViNS @ RG level in the RG with specified ID
@ -291,7 +288,7 @@ class decort_vins(DecortController):
self.result['failed'] = True
self.result['msg'] = ("Current user does not have access to the requested account "
"or non-existent account specified.")
self.fail_json(**self.result)
self.amodule.fail_json(**self.result)
if arg_amodule.params['rg_name'] != "": # at this point we know that rg_id=0
# expect ViNS @ RG level in the RG with specified name under specified account
# RG with the specified name must be present under the account, otherwise abort the module
@ -300,7 +297,7 @@ class decort_vins(DecortController):
rg_facts['status'] in ["DESTROYING", "DESTROYED", "DELETING", "DELETED", "DISABLING", "ENABLING"]):
self.result['failed'] = True
self.result['msg'] = "RG name '{}' not found or has invalid state.".format(arg_amodule.params['rg_name'])
self.fail_json(**self.result)
self.amodule.fail_json(**self.result)
# This call to vins_find may return vins_id=0 if no ViNS with this name found under specified RG
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
account_id=0, # set to 0, as we are looking for ViNS under RG
@ -323,12 +320,13 @@ class decort_vins(DecortController):
# this is "invalid arguments combination" sink
# if we end up here, it means that module was invoked with vins_id=0 and rg_id=0
self.result['failed'] = True
if arg_amodule.params['account_id'] == 0 and arg_amodule.params['account_name'] == "":
self.result['msg'] = "Cannot find ViNS by name"
if arg_amodule.params['account_id'] == 0 and arg_amodule.params['account_name'] == '':
self.result['msg'] = "Cannot find ViNS by name when account name is empty and account ID is 0."
if arg_amodule.params['rg_name'] == "":
# rg_name without account specified
self.result['msg'] = "Cannot find ViNS by name when RG name is empty and RG ID is 0."
self.fail_json(**self.result)
self.amodule.fail_json(**self.result)
return
self.rg_id = validated_rg_id
@ -465,11 +463,6 @@ class decort_vins(DecortController):
ret_dict['ext_ip_addr'] = ""
ret_dict['ext_net_id'] = -1
# arg_vins_facts['vnfs']['GW']['config']
# ext_ip_addr -> ext_net_ip
# ??? -> ext_net_id
# tech_status -> techStatus
return ret_dict
@staticmethod
@ -478,7 +471,7 @@ class decort_vins(DecortController):
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False),
account_id=dict(type='int', required=False,default=0),
account_name=dict(type='str', required=False, default=''),
annotation=dict(type='str', required=False, default=''),
app_id=dict(type='str',
@ -521,7 +514,7 @@ class decort_vins(DecortController):
rg_name=dict(type='str', required=False, default=''),
verify_ssl=dict(type='bool', required=False, default=True),
vins_id=dict(type='int', required=False, default=0),
vins_name=dict(type='str', required=True),
vins_name=dict(type='str', required=False,default=""),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
)
@ -548,6 +541,9 @@ def main():
['app_id', 'app_secret'],
['user', 'password'],
],
required_one_of=[
['vins_id', 'vins_name'],
],
)
decon = decort_vins(amodule)

@ -1,13 +1,10 @@
#
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
# Copyright: (c) 2018-2021 Digital Energy Cloud Solutions LLC
# Copyright: (c) 2018-2023 Digital Energy Cloud Solutions LLC
#
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#
#
# Author: Sergey Shubin (sergey.shubin@digitalenergy.online)
#
"""
This is the library of utility functions and classes for managing DECORT cloud platform.
@ -28,7 +25,7 @@ Requirements:
- PyJWT Python module
- requests Python module
- netaddr Python module
- DECORT cloud platform version 3.6.1 or higher
- DECORT cloud platform version 3.8.6 or higher
"""
import json
@ -39,17 +36,6 @@ import requests
from ansible.module_utils.basic import AnsibleModule
#
# TODO: the following functionality to be implemented and/or tested
# 4) workflow callbacks
# 5) run phase states
# 6) vm_tags - set/manage VM tags
# 7) vm_attributes - change VM attributes (name, annotation) after VM creation - do we need this in Ansible?
# 9) test vm_restore() method and execution plans that involve vm_restore()
#
class DecortController(object):
"""DecortController is a utility class that holds target controller context and handles API requests formatting
based on the requested authentication type.
@ -761,9 +747,12 @@ class DecortController(object):
def kvmvm_provision(self, rg_id,
comp_name, arch,
cpu, ram,
boot_disk, image_id,
boot_disk,
image_id,
annotation="",
userdata=None,
sep_id=None,
pool_name=None,
start_on_create=True):
"""Manage KVM VM provisioning. To remove existing KVM VM compute instance use compute_remove method,
to resize use compute_resize, to manage power state use compute_powerstate method.
@ -808,6 +797,8 @@ class DecortController(object):
cpu=cpu, ram=ram,
imageId=image_id,
bootDisk=boot_disk,
sepId=sep_id,
pool=pool_name,
start=start_on_create, # start_machine parameter requires DECORT API ver 3.3.1 or higher
netType="NONE") # we create VM without any network connections
if userdata:
@ -1189,46 +1180,118 @@ class DecortController(object):
return False
def compute_affinity(self,comp_dict,tags,aff,aaff,label=""):
"""
Manage Compute Tags,Affinitylabel and rules
@param (dict) comp_dict: dictionary of the Compute parameters
@param (dict) tags: dictionary of the tags
@param (list) aff: affinity rules
@param (list) aaff: antiaffinity rules
@param (str) label: affinity group label
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "compute_affinity")
api_params = dict(computeId=comp_dict['id'])
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRulesClear", api_params)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/antiAffinityRulesClear", api_params)
if tags:
for tag in tags:
for tag in tags.items():
if tag not in comp_dict['tags'].items():
api_params = dict(computeId=comp_dict['id'],
key=tag['key'],
value=tag['value'], )
key=tag[0],
value=tag[1], )
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/tagAdd", api_params)
if label:
self.result['failed'] = False
self.result['changed'] = True
for tag in comp_dict['tags'].items():
if tag not in tags.items():
api_params = dict(computeId=comp_dict['id'],
key=tag[0],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/tagRemove", api_params)
self.result['failed'] = False
self.result['changed'] = True
if label and comp_dict['affinityLabel'] != label:
api_params = dict(computeId=comp_dict['id'],
affinityLabel=label,)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityLabelSet", api_params)
if aff:
if len(aff)>0:
for rule in aff:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleAdd", api_params)
if aaff:
if len(aaff)>0:
for rule in aaff:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/antiAffinityRuleAdd", api_params)
self.result['failed'] = False
self.result['changed'] = True
elif label == "" and comp_dict['affinityLabel']:
api_params = dict(computeId=comp_dict['id'])
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityLabelRemove", api_params)
self.result['failed'] = False
self.result['changed'] = True
self.result['failed'] = False
self.result['changed'] = True
affrule_del = []
affrule_add = []
aaffrule_del = []
aaffrule_add = []
#AFFINITY
for rule in comp_dict['affinityRules']:
del rule['guid']
if rule not in aff:
affrule_del.append(rule)
for rule in aff:
if rule not in comp_dict['affinityRules']:
affrule_add.append(rule)
#ANTI AFFINITY
for rule in comp_dict['antiAffinityRules']:
del rule['guid']
if rule not in aaff:
aaffrule_del.append(rule)
for rule in aaff:
if rule not in comp_dict['antiAffinityRules']:
aaffrule_add.append(rule)
#AFFINITY
if len (affrule_del):
for rule in affrule_del:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleRemove", api_params)
self.result['failed'] = False
self.result['changed'] = True
if len(affrule_add)>0:
for rule in affrule_add:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleAdd", api_params)
self.result['failed'] = False
self.result['changed'] = True
#ANTI AFFINITY
if len(aaffrule_del):
for rule in aaffrule_del:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/antiAffinityRuleRemove", api_params)
self.result['failed'] = False
self.result['changed'] = True
if len(aaffrule_add)>0:
for rule in aaffrule_add:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
value=rule['value'],
topology=rule['topology'],
mode=rule['mode'],
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/antiAffinityRuleAdd", api_params)
self.result['failed'] = False
self.result['changed'] = True
return
###################################
# OS image manipulation methods
###################################
@ -1571,15 +1634,18 @@ class DecortController(object):
self.result['msg'] = "rg_find(): cannot find RG by name if account ID is zero or less."
self.amodule.fail_json(**self.result)
# try to locate RG by name - start with getting all RGs IDs within the specified account
api_params['accountId'] = arg_account_id
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/listRG", api_params)
#api_params['accountId'] = arg_account_id
api_params['includedeleted'] = False
#api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/listRG", api_params)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/list",api_params)
if api_resp.status_code == 200:
account_specs = json.loads(api_resp.content.decode('utf8'))
api_params.pop('accountId')
#api_params.pop('accountId')
for rg_item in account_specs:
got_id, got_specs = self._rg_get_by_id(rg_item['id'])
if got_id and got_specs['name'] == arg_rg_name:
#
if rg_item['name'] == arg_rg_name:
# name matches
got_id, got_specs = self._rg_get_by_id(rg_item['id'])
if not arg_check_state or got_specs['status'] not in RG_INVALID_STATES:
ret_rg_id = got_id
ret_rg_dict = got_specs
@ -2595,6 +2661,53 @@ class DecortController(object):
# Disk management
#
##############################
def disk_check_iotune_arg(self,iotune_list):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "disk_check_iotune_arg")
MIN_IOPS = 80
total_bytes_sec=iotune_list['total_bytes_sec']
read_bytes_sec=iotune_list['read_bytes_sec']
write_bytes_sec=iotune_list['write_bytes_sec']
total_iops_sec=iotune_list['total_iops_sec']
read_iops_sec=iotune_list['read_iops_sec']
write_iops_sec=iotune_list['write_iops_sec']
total_bytes_sec_max=iotune_list['total_bytes_sec_max']
read_bytes_sec_max=iotune_list['read_bytes_sec_max']
write_bytes_sec_max=iotune_list['write_bytes_sec_max']
total_iops_sec_max=iotune_list['total_iops_sec_max']
read_iops_sec_max=iotune_list['read_iops_sec_max']
write_iops_sec_max=iotune_list['write_iops_sec_max']
size_iops_sec=iotune_list['size_iops_sec']
if total_iops_sec and (read_iops_sec or write_iops_sec):
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = (f"total and read/write of iops_sec cannot be set at the same time")
if total_bytes_sec and (read_bytes_sec or write_bytes_sec):
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = (f"total and read/write of bytes_sec cannot be set at the same time")
if total_bytes_sec_max and (read_bytes_sec_max or write_bytes_sec_max):
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] =(f"total and read/write of bytes_sec_max cannot be set at the same time")
if total_iops_sec_max and (read_iops_sec_max or write_iops_sec_max):
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] =(f"total and read/write of iops_sec_max cannot be set at the same time")
for arg, val in iotune_list.items():
if arg in (
"total_iops_sec",
"read_iops_sec",
"write_iops_sec",
"total_iops_sec_max",
"read_iops_sec_max",
"write_iops_sec_max",
"size_iops_sec",
):
if val and val < self.MIN_IOPS:
self.result['msg'] = (f"{arg} was set below the minimum iops {MIN_IOPS}: {val} provided")
return
def disk_delete(self, disk_id, permanently, detach, reason):
"""Deletes specified Disk.
@ -2654,7 +2767,7 @@ class DecortController(object):
return ret_disk_id, ret_disk_dict
def disk_find(self, disk_id, name, account_id, check_state=False):
def disk_find(self, disk_id=0, name="", account_id=0, check_state=False):
"""Find specified Disk.
@param (int) disk_id: ID of the Disk. If non-zero disk_id is specified, all other arguments
@ -2678,13 +2791,13 @@ class DecortController(object):
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = "disk_find() in check mode: find Disk ID {} / name '{}' was requested.".format(disk_id,
disk_name)
name)
return
ret_disk_id = 0
ret_disk_facts = None
if disk_id > 0:
if disk_id:
ret_disk_id, ret_disk_facts = self._disk_get_by_id(disk_id)
if not ret_disk_id:
self.result['failed'] = True
@ -2694,19 +2807,20 @@ class DecortController(object):
return ret_disk_id, ret_disk_facts
else:
return 0, None
elif name != "":
if account_id > 0:
api_params = dict(accountId=account_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/list", api_params)
elif name:
if account_id:
api_params = dict(accountId=account_id,name=name)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/search", api_params)
# the above call may return more than one matching disk
disks_list = json.loads(api_resp.content.decode('utf8'))
for runner in disks_list:
# return the first disk of the specified name that fulfills status matching rule
if runner['name'] == name:
if not check_state or runner['status']:
return runner['id'], runner
else:
if len(disks_list) == 0:
return 0, None
elif len(disks_list) > 1:
self.result['failed'] = True
self.result['msg'] = "disk_find(): Found more then one Disk with Name: {}.".format(name)
self.amodule.fail_json(**self.result)
else:
return disks_list[0]['id'], disks_list[0]
else: # we are missing meaningful account_id - fail the module
self.result['failed'] = True
self.result['msg'] = ("disk_find(): cannot find Disk by name '{}' "
@ -2719,7 +2833,7 @@ class DecortController(object):
return 0, None
def disk_create(self, accountId, gid, name, description, size, type, iops, sep_id, pool):
def disk_create(self, accountId, name, description, size, type, 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
@ -2739,13 +2853,13 @@ class DecortController(object):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "disk_creation")
api_params = dict(accountId=accountId,
gid=gid,
gid=0, # depricated
name=name,
description=description,
size=size,
type=type,
iops=iops,
sepId=sep_id,
sep_id=sep_id,
pool=pool )
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/create", api_params)
if api_resp.status_code == 200:
@ -2807,32 +2921,21 @@ class DecortController(object):
return
def disk_limitIO(self, limits, diskId):
def disk_limitIO(self,disk_id, limits):
"""Limits already created Disk identified by its ID.
@param (dict) limits: Dictionary with limits.
@param (int) diskId: ID of the Disk to limit.
@returns: nothing on success. On error this method will abort module execution.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "disk_limitIO")
api_params = dict(diskId=diskId,
total_bytes_sec=limits['total_bytes_sec'],
read_bytes_sec=limits['read_bytes_sec'],
write_bytes_sec=limits['write_bytes_sec'],
total_iops_sec=limits['total_iops_sec'],
read_iops_sec=limits['read_iops_sec'],
write_iops_sec=limits['write_iops_sec'],
total_bytes_sec_max=limits['total_bytes_sec_max'],
read_bytes_sec_max=limits['read_bytes_sec_max'],
write_bytes_sec_max=limits['write_bytes_sec_max'],
total_iops_sec_max=limits['total_iops_sec_max'],
read_iops_sec_max=limits['read_iops_sec_max'],
write_iops_sec_max=limits['write_iops_sec_max'],
size_iops_sec=limits['size_iops_sec'])
api_params = dict(diskId=disk_id,
**limits)
self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/limitIO", api_params)
self.result['msg'] = "Specified Disk ID {} limited successfully.".format(self.validated_disk_id)
self.result['changed'] = True
self.result['msg'] = "Specified Disk ID {} limited successfully.".format(disk_id)
return
def disk_rename(self, diskId, name):
def disk_rename(self, disk_id, name):
"""Renames disk to the specified new name.
@param disk_id: ID of the Disk to rename.
@ -2841,12 +2944,13 @@ class DecortController(object):
@returns: nothing on success. On error this method will abort module execution.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "disk_rename")
api_params = dict(diskId=diskId,
api_params = dict(diskId=disk_id,
name=name)
self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/rename", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
self.result['failed'] = False
self.result['changed'] = True
self.result['msg'] = ("Disk with id '{}',successfully renamed to '{}'.").format(disk_id, name)
return
def disk_restore(self, disk_id):
@ -2872,6 +2976,30 @@ class DecortController(object):
self.result['failed'] = False
self.result['changed'] = True
return
def disk_share(self, disk_id, share='false'):
"""Share data disk
@param disk_id: ID of the Disk to share.
@param share: share status of the disk
@returns: nothing on success. On error this method will abort module execution.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "disk_share")
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = "disk_share() in check mode: share Disk ID {} was requested.".format(disk_id)
return
api_params = dict(diskId=disk_id)
if share:
self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/share", api_params)
else:
self.decort_api_call(requests.post, "/restmachine/cloudapi/disks/unshare", api_params)
# On success the above call will return here. On error it will abort execution by calling fail_json.
self.result['failed'] = False
self.result['changed'] = True
return
##############################
#
@ -3140,6 +3268,10 @@ class DecortController(object):
for k8s_item in k8s_list:
if k8s_item['name'] == k8s_name and k8s_item['rgId'] == rg_id:
if not check_state or k8s_item['status'] not in K8S_INVALID_STATES:
# TODO: rework after k8s/get wilb be updated
self.k8s_vins_id = None
self.k8s_vins_id = k8s_item['vinsId']
#
ret_k8s_id = k8s_item['id']
_, ret_k8s_dict = self._k8s_get_by_id(ret_k8s_id)
@ -3264,7 +3396,7 @@ class DecortController(object):
return
def k8s_provision(self, k8s_name,
k8ci_id,rg_id, master_count,
k8ci_id,rg_id,plugin,master_count,
master_cpu, master_ram,
master_disk, default_worker, extnet_id,
with_lb, annotation, ):
@ -3290,6 +3422,7 @@ class DecortController(object):
rgId=rg_id,
k8ciId=k8ci_id,
workerGroupName=def_wg_name,
networkPlugin=plugin,
masterNum=master_count,
masterCpu=master_cpu,
masterRam=master_ram,
@ -3326,6 +3459,7 @@ class DecortController(object):
return
elif ret_info['status'] == "OK":
k8s_id = ret_info['result']
self.result['msg'] = f"k8s_provision(): K8s cluster {k8s_name} created successful"
self.result['changed'] = True
return k8s_id
else:
@ -3339,6 +3473,9 @@ class DecortController(object):
else:
self.result['msg'] = ("k8s_provision(): Can't create cluster")
self.result['failed'] = True
self.result['changed'] = False
self.fail_json(**self.result)
return
def k8s_workers_modify(self,arg_k8swg,arg_modwg):

Loading…
Cancel
Save