You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
decort-ansible/library/decort_rg.py

416 lines
16 KiB

#!/usr/bin/python
DOCUMENTATION = r'''
---
module: decort_rg
description: See L(Module Documentation,https://repository.basistech.ru/BASIS/decort-ansible/wiki/Home).
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
class decort_rg(DecortController):
def __init__(self):
super(decort_rg, self).__init__(AnsibleModule(**self.amodule_init_args))
amodule = self.amodule
self.validated_acc_id = 0
self.validated_rg_id = 0
self.validated_rg_facts = None
if amodule.params['rg_id'] is None:
if self.amodule.params['account_id']:
self.validated_acc_id, _ = self.account_find("", amodule.params['account_id'])
elif amodule.params['account_name']:
self.validated_acc_id, _ = self.account_find(amodule.params['account_name'])
if not self.validated_acc_id:
# we failed to locate account by either name or ID - abort with an error
self.result['failed'] = True
self.result['msg'] = ("Current user does not have access to the requested account "
"or non-existent account specified.")
self.amodule.fail_json(**self.result)
# Check if the RG with the specified parameters already exists
self.get_info()
if amodule.params['state'] != "absent":
self.rg_should_exist = True
else:
self.rg_should_exist = False
def get_info(self):
# If this is the first getting info
if not self.validated_rg_id:
self.validated_rg_id, self.rg_facts = self.rg_find(
arg_account_id=self.validated_acc_id,
arg_rg_id=self.aparams['rg_id'],
arg_rg_name=self.aparams['rg_name'],
arg_check_state=False,
)
# If this is a repeated getting info
else:
# If check mode is enabled, there is no needed to
# request info again
if self.amodule.check_mode:
return
_, self.rg_facts = self.rg_find(arg_rg_id=self.validated_rg_id)
def access(self):
should_change_access = False
acc_granted = False
for rg_item in self.rg_facts['acl']:
if rg_item['userGroupId'] == self.amodule.params['access']['user']:
acc_granted = True
if self.amodule.params['access']['action'] == 'grant':
if rg_item['right'] != self.amodule.params['access']['right']:
should_change_access = True
if self.amodule.params['access']['action'] == 'revoke':
should_change_access = True
if acc_granted == False and self.amodule.params['access']['action'] == 'grant':
should_change_access = True
if should_change_access == True:
self.rg_access(self.validated_rg_id, self.amodule.params['access'])
self.rg_facts['access'] = self.amodule.params['access']
self.rg_should_exist = True
return
def error(self):
self.result['failed'] = True
self.result['changed'] = False
if self.validated_rg_id > 0:
self.result['msg'] = ("Invalid target state '{}' requested for rg ID {} in the "
"current status '{}'.").format(self.validated_rg_id,
self.amodule.params['state'],
self.rg_facts['status'])
else:
self.result['msg'] = ("Invalid target state '{}' requested for non-existent rg name '{}' "
"in account ID {} ").format(self.amodule.params['state'],
self.amodule.params['rg_name'],
self.validated_acc_id)
return
def update(self):
resources = self.rg_facts['Resources']['Reserved']
incorrect_quota = dict(Requested=dict(),
Reserved=dict(),)
query_key_map = dict(cpu='cpu',
ram='ram',
disk='disksize',
ext_ips='extips',
net_transfer='exttraffic',)
if self.amodule.params['quotas']:
for quota_item in self.amodule.params['quotas']:
if self.amodule.params['quotas'][quota_item] < resources[query_key_map[quota_item]]:
incorrect_quota['Requested'][quota_item]=self.amodule.params['quotas'][quota_item]
incorrect_quota['Reserved'][quota_item]=resources[query_key_map[quota_item]]
if incorrect_quota['Requested']:
self.result['msg'] = ("Cannot limit less than already reserved'{}'").format(incorrect_quota)
self.result['failed'] = True
if not self.result['failed']:
self.rg_update(
arg_rg_dict=self.rg_facts,
arg_quotas=self.amodule.params['quotas'],
arg_res_types=self.amodule.params['resType'],
arg_newname=self.amodule.params['rename'],
arg_sep_pools=self.amodule.params['sep_pools'],
)
self.rg_should_exist = True
return
def setDefNet(self):
rg_def_net_type = self.rg_facts['def_net_type']
rg_def_net_id = self.rg_facts['def_net_id']
aparam_def_net_type = self.aparams['def_netType']
aparam_def_net_id = self.aparams['def_netId']
need_to_reset = (aparam_def_net_type == 'NONE'
and rg_def_net_type != aparam_def_net_type)
need_to_change = False
if aparam_def_net_id is not None:
need_to_change = (aparam_def_net_id != rg_def_net_id
or aparam_def_net_type != rg_def_net_type)
if need_to_reset or need_to_change:
self.rg_setDefNet(
arg_rg_id=self.validated_rg_id,
arg_net_type=aparam_def_net_type,
arg_net_id=aparam_def_net_id,
)
self.rg_should_exist = True
return
def create(self):
self.validated_rg_id = self.rg_provision(self.validated_acc_id,
self.amodule.params['rg_name'],
self.amodule.params['owner'],
self.amodule.params['description'],
self.amodule.params['resType'],
self.amodule.params['def_netType'],
self.amodule.params['ipcidr'],
self.amodule.params['extNetId'],
self.amodule.params['extNetIp'],
self.amodule.params['quotas'],
"", # this is location code. TODO: add module argument
)
if self.validated_rg_id:
self.validated_rg_id, self.rg_facts = self.rg_find(
arg_account_id=self.validated_acc_id,
arg_rg_id=self.validated_rg_id,
arg_rg_name="",
arg_check_state=False
)
self.rg_should_exist = True
return
def enable(self):
self.rg_enable(self.validated_rg_id,
self.amodule.params['state'])
if self.amodule.params['state'] == "enabled":
self.rg_facts['status'] = 'CREATED'
else:
self.rg_facts['status'] = 'DISABLED'
self.rg_should_exist = True
return
def restore(self):
self.rg_restore(self.validated_rg_id)
self.rg_facts['status'] = 'DISABLED'
self.rg_should_exist = True
return
def destroy(self):
self.rg_delete(
rg_id=self.validated_rg_id,
permanently=self.amodule.params['permanently'],
recursively=self.aparams['recursive_deletion'],
)
if self.amodule.params['permanently'] == True:
self.rg_facts['status'] = 'DESTROYED'
else:
self.rg_facts['status'] = 'DELETED'
self.rg_should_exist = False
return
def package_facts(self, check_mode=False):
"""Package a dictionary of RG facts according to the decort_rg module specification. This dictionary will
be returned to the upstream Ansible engine at the completion of the module run.
@param arg_rg_facts: dictionary with RG facts as returned by API call to .../rg/get
@param arg_check_mode: boolean that tells if this Ansible module is run in check mode
"""
ret_dict = dict(id=0,
name="none",
state="CHECK_MODE",
)
if check_mode:
# in check mode return immediately with the default values
return ret_dict
#if arg_rg_facts is None:
# # if void facts provided - change state value to ABSENT and return
# ret_dict['state'] = "ABSENT"
# return ret_dict
ret_dict['id'] = self.rg_facts['id']
ret_dict['name'] = self.rg_facts['name']
ret_dict['state'] = self.rg_facts['status']
ret_dict['account_id'] = self.rg_facts['accountId']
ret_dict['gid'] = self.rg_facts['gid']
ret_dict['quota'] = self.rg_facts['resourceLimits']
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']
ret_dict['uniqPools'] = self.rg_facts['uniqPools']
return ret_dict
@property
def amodule_init_args(self) -> dict:
return self.pack_amodule_init_args(
argument_spec=dict(
account_id=dict(
type='int',
),
account_name=dict(
type='str',
default='',
),
access=dict(
type='dict',
),
description=dict(
type='str',
default='',
),
def_netType=dict(
type='str',
choices=[
'PRIVATE',
'PUBLIC',
'NONE',
],
default='PRIVATE',
),
def_netId=dict(
type='int',
),
extNetId=dict(
type='int',
default=0,
),
extNetIp=dict(
type='str',
default='',
),
owner=dict(
type='str',
default='',
),
ipcidr=dict(
type='str',
default='',
),
rename=dict(
type='str',
default='',
),
quotas=dict(
type='dict',
),
resType=dict(
type='list',
),
state=dict(
type='str',
default='present',
choices=[
'absent',
'disabled',
'enabled',
'present',
],
),
permanently=dict(
type='bool',
default='False',
),
rg_name=dict(
type='str',
),
rg_id=dict(
type='int',
),
sep_pools=dict(
type='list',
elements='dict',
options=dict(
sep_id=dict(
type='int',
required=True,
),
pool_names=dict(
type='list',
required=True,
elements='str',
),
),
),
recursive_deletion=dict(
type='bool',
default=False,
)
),
supports_check_mode=True,
)
# Workflow digest:
# 1) authenticate to DECORT controller & validate authentication by issuing API call - done when creating DECORTController
# 2) check if the RG with the specified id or rg_name:name exists
# 3) if RG does not exist -> deploy
# 4) if RG exists: check desired state, desired configuration -> initiate action accordingly
# 5) report result to Ansible
def main():
decon = decort_rg()
amodule = decon.amodule
#amodule.check_mode=True
if decon.validated_rg_id > 0:
if decon.rg_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING", "CONFIRMED"]:
decon.error()
elif decon.rg_facts['status'] in ("CREATED"):
if amodule.params['state'] == 'absent':
decon.destroy()
elif amodule.params['state'] == "disabled":
decon.enable()
if amodule.params['state'] in ['present', 'enabled']:
if (
amodule.params['quotas']
or amodule.params['resType']
or amodule.params['rename'] != ""
or amodule.params['sep_pools'] is not None
):
decon.update()
if amodule.params['access']:
decon.access()
if amodule.params['def_netType'] is not None:
decon.setDefNet()
elif decon.rg_facts['status'] == "DELETED":
if amodule.params['state'] == 'absent' and amodule.params['permanently'] == True:
decon.destroy()
elif (amodule.params['state'] == 'present'
or amodule.params['state'] == 'disabled'):
decon.restore()
elif amodule.params['state'] == 'enabled':
decon.restore()
decon.enable()
elif decon.rg_facts['status'] in ("DISABLED"):
if amodule.params['state'] == 'absent':
decon.destroy()
elif amodule.params['state'] == ("enabled"):
decon.enable()
else:
if amodule.params['state'] in ('present', 'enabled'):
if not amodule.params['rg_name']:
decon.result['failed'] = True
decon.result['msg'] = (
'Resource group could not be created because'
' the "rg_name" parameter was not specified.'
)
else:
decon.create()
if amodule.params['access'] and not amodule.check_mode:
decon.access()
elif amodule.params['state'] in ('disabled'):
decon.error()
if decon.result['failed']:
amodule.fail_json(**decon.result)
else:
if decon.rg_should_exist:
if decon.result['changed']:
decon.get_info()
decon.result['facts'] = decon.package_facts(amodule.check_mode)
amodule.exit_json(**decon.result)
else:
amodule.exit_json(**decon.result)
if __name__ == "__main__":
main()