added LB module & some other fix

rc-5.2.3
Alex_geth 2 years ago
parent dd28084b76
commit 889618f843

@ -0,0 +1,328 @@
#!/usr/bin/python
#
# Digital Enegry Cloud Orchestration Technology (DECORT) modules for Ansible
# Copyright: (c) 2018-2022 Digital Energy Cloud Solutions LLC
#
# Apache License 2.0 (see http://www.apache.org/licenses/LICENSE-2.0.txt)
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
TODO
'''
EXAMPLES = '''
TODO
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import *
class decort_lb(DecortController):
def __init__(self,arg_amodule) -> None:
super(decort_lb,self).__init__(arg_amodule)
self.lb_id = 0
self.lb_facts = None
self.vins_id = 0
self.vins_facts = None
self.rg_id = 0
self.rg_facts = None
self.acc_id = 0
self.acc_facts = None
self.default_server_check = "enabled"
self.default_alg = "roundrobin"
self.default_settings = {
"downinter": 10000,
"fall": 2,
"inter": 5000,
"maxconn": 250,
"maxqueue": 256,
"rise": 2,
"slowstart": 60000,
"weight": 100,
}
if arg_amodule.params['lb_id']:
self.lb_id, self.lb_facts = self.lb_find(arg_amodule.params['lb_id'])
if not self.lb_id:
self.result['failed'] = True
self.result['msg'] = "Specified LB ID {} not found."\
.format(arg_amodule.params['lb _id'])
self.fail_json(**self.result)
self.acc_id = self.lb_facts['accountId']
self.rg_id = self.lb_facts['rgId']
self.vins_id = self.lb_facts['vinsId']
return
if arg_amodule.params['rg_id']:
self.rg_id, self.rg_facts = self.rg_find(0,arg_amodule.params['rg_id'], arg_rg_name="")
if not self.rg_id:
self.result['failed'] = True
self.result['msg'] = "Specified RG ID {} not found.".format(arg_amodule.params['vins_id'])
self.fail_json(**self.result)
if arg_amodule.params['vins_id']:
self.vins_id, self.vins_facts = self.vins_find(arg_amodule.params['vins_id'])
if not self.vins_id:
self.result['failed'] = True
self.result['msg'] = "Specified ViNS ID {} not found.".format(arg_amodule.params['vins_id'])
self.fail_json(**self.result)
elif arg_amodule.params['account_id'] or arg_amodule.params['account_name'] != "":
if arg_amodule.params['rg_name']:
self.result['failed'] = True
self.result['msg'] = ("RG name must be specified with account present")
self.fail_json(**self.result)
self.acc_id, self.acc_facts = self.account_find(arg_amodule.params['account_name'],
arg_amodule.params['account_id'])
if not self.acc_id:
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.rg_id, self.rg_facts = self.rg_find(self._acc_id,0, arg_rg_name=arg_amodule.params['rg_name'])
if self.rg_id and self.vins_id:
self.lb_id, self.lb_facts = self.lb_find(0,arg_amodule.params['lb_name'],self.rg_id)
return
def create(self):
self.lb_id = self.lb_provision(self.amodule.params['lb_name'],
self.rg_id,self.vins_id,
self.amodule.params['ext_net_id'],
self.amodule.params['annotation'])
if self.amodule.params['backends'] or self.amodule.params['frontends']:
self.lb_id, self.lb_facts = self.lb_find(0,self.amodule.params['lb_name'],self.rg_id)
self.lb_update(
self.lb_facts['backends'],
self.lb_facts['frontends'],
self.amodule.params['backends'],
self.amodule.params['servers'],
self.amodule.params['frontends']
)
return
def action(self,d_state='',restore=False):
if restore == True:
self.lb_restore(arg_vins_id=self.lb_id)
self.lb_state(self.vins_facts, 'enabled')
self.lb_facts['status'] = "ENABLED"
self.lb_facts['techStatus'] = "STARTED"
self.lb_update(
self.lb_facts['backends'],
self.lb_facts['frontends'],
self.amodule.params['backends'],
self.amodule.params['servers'],
self.amodule.params['frontends']
)
if d_state != '':
self.lb_state(self.lb_facts, d_state)
return
def delete(self):
self.lb_delete(self.lb_id, self.amodule.params['permanently'])
self.lb_facts['status'] = 'DESTROYED'
return
def nop(self):
"""No operation (NOP) handler for LB management by decort_lb module.
This function is intended to be called from the main switch construct of the module
when current state -> desired state change logic does not require any changes to
the actual LB state.
"""
self.result['failed'] = False
self.result['changed'] = False
if self.lb_id:
self.result['msg'] = ("No state change required for LB ID {} because of its "
"current status '{}'.").format(self.lb_id, self.vins_facts['status'])
else:
self.result['msg'] = ("No state change to '{}' can be done for "
"non-existent LB instance.").format(self.amodule.params['state'])
return
def error(self):
self.result['failed'] = True
self.result['changed'] = False
if self.vins_id:
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = ("Invalid target state '{}' requested for LB ID {} in the "
"current status '{}'").format(self.lb_id,
self.amodule.params['state'],
self.lb_facts['status'])
else:
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = ("Invalid target state '{}' requested for non-existent "
"LB name '{}'").format(self.amodule.params['state'],
self.amodule.params['lb_name'])
return
def package_facts(self, arg_check_mode=False):
"""Package a dictionary of LB facts according to the decort_lb module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of
the module run.
@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 arg_check_mode:
# in check mode return immediately with the default values
return ret_dict
if self.vins_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.lb_facts['id']
ret_dict['name'] = self.lb_facts['name']
ret_dict['state'] = self.lb_facts['status']
#ret_dict['account_id'] = self.lb_facts['accountId']
ret_dict['rg_id'] = self.lb_facts['rgId']
ret_dict['gid'] = self.lb_facts['gid']
if self.amodule.params['state']!="absent":
ret_dict['backends'] = self.lb_facts['backends']
ret_dict['frontends'] = self.lb_facts['frontends']
return ret_dict
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
by AnsibleModule utility class."""
return dict(
account_id=dict(type='int', required=False),
account_name=dict(type='str', required=False, default=''),
annotation=dict(type='str', required=False, default='Managed by Ansible module decort_lb'),
app_id=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_APP_ID'])),
app_secret=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_APP_SECRET']),
no_log=True),
authenticator=dict(type='str',
required=True,
choices=['legacy', 'oauth2', 'jwt']),
controller_url=dict(type='str', required=True),
# datacenter=dict(type='str', required=False, default=''),
ext_net_id=dict(type='int', required=False, default=-1),
ext_ip_addr=dict(type='str', required=False, default=''),
jwt=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_JWT']),
no_log=True),
oauth2_url=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_OAUTH2_URL'])),
password=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_PASSWORD']),
no_log=True),
state=dict(type='str',
default='present',
choices=['absent', 'disabled', 'enabled', 'present','restart']),
user=dict(type='str',
required=False,
fallback=(env_fallback, ['DECORT_USER'])),
rg_id=dict(type='int', required=False, default=0),
rg_name=dict(type='str', required=False, default=''),
vins_name=dict(type='str', required=False, default=''),
vins_id=dict(type='int', required=False, default=0),
verify_ssl=dict(type='bool', required=False, default=True),
lb_id=dict(type='int', required=False, default=0),
lb_name=dict(type='str', required=True),
backends=dict(type='list',required=False,default=[]),
frontends=dict(type='list',required=False,default=[]),
servers=dict(type='list',required=False,default=[]),
permanently=dict(type='bool', required=False, default=False),
workflow_callback=dict(type='str', required=False),
workflow_context=dict(type='str', required=False),
)
def main():
module_parameters = decort_lb.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
mutually_exclusive=[
['oauth2', 'password'],
['password', 'jwt'],
['jwt', 'oauth2'],
],
required_together=[
['app_id', 'app_secret'],
['user', 'password']
],
required_one_of=[
['rg_id','rg_name'],
['lb_id','lb_name'],
['vins_id','vins_name']
]
)
decon = decort_lb(amodule)
if decon.lb_id:
if decon.lb_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING","DESTROYING","RESTORING"]:
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("No change can be done for existing LB ID {} because of its current "
"status '{}'").format(decon.lb_id, decon.lb_facts['status'])
elif decon.lb_facts['status'] == "DISABLED":
if amodule.params['state'] == 'absent':
decon.delete()
elif amodule.params['state'] in ('present', 'disabled'):
decon.action()
elif amodule.params['state'] == 'enabled':
decon.action('enabled')
elif decon.lb_facts['status'] in ["CREATED", "ENABLED"]:
if amodule.params['state'] == 'absent':
decon.delete()
elif amodule.params['state'] in ('present', 'enabled'):
decon.action()
elif amodule.params['state'] == 'disabled':
decon.action('disabled')
elif amodule.params['state'] in ('stopped', 'started','restart'):
decon.action(amodule.params['state'])
elif decon.lb_facts['status'] == "DELETED":
if amodule.params['state'] in ['present', 'enabled']:
decon.action(restore=True)
elif amodule.params['state'] == 'absent':
decon.delete()
elif amodule.params['state'] == 'disabled':
decon.error()
elif decon.lb_facts['status'] == "DESTROYED":
if amodule.params['state'] in ('present', 'enabled'):
decon.create()
elif amodule.params['state'] == 'absent':
decon.nop()
elif amodule.params['state'] == 'disabled':
decon.error()
else:
if amodule.params['state'] == 'absent':
decon.nop()
elif amodule.params['state'] in ('present', 'enabled'):
decon.create()
elif amodule.params['state'] == 'disabled':
decon.error()
if decon.result['failed']:
amodule.fail_json(**decon.result)
else:
if decon.result['changed'] and amodule.params['state'] != 'absent':
_, decon.lb_facts = decon.lb_find(decon.lb_id)
if decon.lb_id:
decon.result['facts'] = decon.package_facts(amodule.check_mode)
amodule.exit_json(**decon.result)
if __name__ == "__main__":
main()

@ -249,8 +249,8 @@ class decort_vins(DecortController):
def __init__(self,arg_amodule): def __init__(self,arg_amodule):
super(decort_vins, self).__init__(arg_amodule) super(decort_vins, self).__init__(arg_amodule)
vins_id = 0 self.vins_id = 0
vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level self.vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
vins_facts = None # will hold ViNS facts vins_facts = None # will hold ViNS facts
validated_rg_id = 0 validated_rg_id = 0
rg_facts = None # will hold RG facts rg_facts = None # will hold RG facts
@ -261,17 +261,17 @@ class decort_vins(DecortController):
# expect existing ViNS with the specified 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 # 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']) self.vins_id, self.vins_facts = self.vins_find(arg_amodule.params['vins_id'])
if not vins_id: if not self.vins_id:
self.result['failed'] = True self.result['failed'] = True
self.result['msg'] = "Specified ViNS ID {} not found.".format(arg_amodule.params['vins_id']) self.result['msg'] = "Specified ViNS ID {} not found.".format(arg_amodule.params['vins_id'])
self.fail_json(**self.result) self.fail_json(**self.result)
vins_level = "ID" self.vins_level = "ID"
validated_acc_id = vins_facts['accountId'] validated_acc_id = vins_facts['accountId']
validated_rg_id = vins_facts['rgId'] validated_rg_id = vins_facts['rgId']
elif arg_amodule.params['rg_id']: elif arg_amodule.params['rg_id']:
# expect ViNS @ RG level in the RG with specified ID # expect ViNS @ RG level in the RG with specified ID
vins_level = "RG" self.vins_level = "RG"
# This call to rg_find will abort the module if no RG with such ID is present # This call to rg_find will abort the module if no RG with such ID is present
validated_rg_id, rg_facts = self.rg_find(0, # account ID set to 0 as we search for RG by RG ID validated_rg_id, rg_facts = self.rg_find(0, # account ID set to 0 as we search for RG by RG ID
arg_amodule.params['rg_id'], arg_rg_name="") arg_amodule.params['rg_id'], arg_rg_name="")
@ -307,7 +307,7 @@ class decort_vins(DecortController):
rg_id=validated_rg_id, rg_id=validated_rg_id,
rg_facts=rg_facts, rg_facts=rg_facts,
check_state=False) check_state=False)
vins_level = "RG" self.vins_level = "RG"
# TODO: add checks and setup ViNS presence flags accordingly # TODO: add checks and setup ViNS presence flags accordingly
else: # At this point we know for sure that rg_name="" and rg_id=0 else: # At this point we know for sure that rg_name="" and rg_id=0
# So we expect ViNS @ account level # So we expect ViNS @ account level
@ -317,7 +317,7 @@ class decort_vins(DecortController):
rg_id=0, rg_id=0,
rg_facts=rg_facts, rg_facts=rg_facts,
check_state=False) check_state=False)
vins_level = "ACC" self.vins_level = "ACC"
# TODO: add checks and setup ViNS presence flags accordingly # TODO: add checks and setup ViNS presence flags accordingly
else: else:
# this is "invalid arguments combination" sink # this is "invalid arguments combination" sink

@ -31,7 +31,6 @@ Requirements:
- DECORT cloud platform version 3.6.1 or higher - DECORT cloud platform version 3.6.1 or higher
""" """
import copy
import json import json
import jwt import jwt
import netaddr import netaddr
@ -1207,7 +1206,7 @@ class DecortController(object):
affinityLabel=label,) affinityLabel=label,)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityLabelSet", api_params) self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityLabelSet", api_params)
if aff: if aff:
if len(aff[0])>0: if len(aff)>0:
for rule in aff: for rule in aff:
api_params = dict(computeId=comp_dict['id'], api_params = dict(computeId=comp_dict['id'],
key=rule['key'], key=rule['key'],
@ -1217,7 +1216,7 @@ class DecortController(object):
policy=rule['policy'],) policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleAdd", api_params) self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleAdd", api_params)
if aaff: if aaff:
if len(aaff[0])>0: if len(aaff)>0:
for rule in aaff: for rule in aaff:
api_params = dict(computeId=comp_dict['id'], api_params = dict(computeId=comp_dict['id'],
key=rule['key'], key=rule['key'],
@ -1975,7 +1974,7 @@ class DecortController(object):
if api_resp.status_code == 200: if api_resp.status_code == 200:
locations = json.loads(api_resp.content.decode('utf8')) locations = json.loads(api_resp.content.decode('utf8'))
if location_code == "" and locations: if location_code == "" and locations:
ret_gid = locations[0]['gid'] ret_gid = locations['gid']
else: else:
for runner in locations: for runner in locations:
if runner['locationCode'] == location_code: if runner['locationCode'] == location_code:
@ -2060,7 +2059,7 @@ class DecortController(object):
self.result['msg'] = "_rg_listvins(): zero RG ID specified." self.result['msg'] = "_rg_listvins(): zero RG ID specified."
self.amodule.fail_json(**self.result) self.amodule.fail_json(**self.result)
api_params = dict(rgId=rg_id, ) api_params = dict(rgId=rg_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/listVins", api_params) api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/listVins", api_params)
if api_resp.status_code == 200: if api_resp.status_code == 200:
ret_rg_vins_list = json.loads(api_resp.content.decode('utf8')) ret_rg_vins_list = json.loads(api_resp.content.decode('utf8'))
@ -3270,7 +3269,7 @@ class DecortController(object):
self.result['failed'] = True self.result['failed'] = True
return return
elif ret_info['status'] == "OK": elif ret_info['status'] == "OK":
k8s_id = ret_info['result'][0] k8s_id = ret_info['result']
self.result['changed'] = True self.result['changed'] = True
return k8s_id return k8s_id
else: else:
@ -3365,18 +3364,17 @@ class DecortController(object):
api_params = dict(includeDisabled=False) api_params = dict(includeDisabled=False)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/k8ci/list", api_params) api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/k8ci/list", api_params)
k8ci_id_present = False
if api_resp.status_code == 200: if api_resp.status_code == 200:
ret_k8ci_list = json.loads(api_resp.content.decode('utf8')) ret_k8ci_list = json.loads(api_resp.content.decode('utf8'))
for k8ci_item in ret_k8ci_list: for k8ci_item in ret_k8ci_list:
if k8ci_item['id'] == arg_k8ci_id: if k8ci_item['id'] == arg_k8ci_id:
k8ci_id_present = True
break break
if k8ci_id_present == False: else:
self.result['failed'] = True self.result['failed'] = True
self.result['msg'] = ("Cannot find k8ci id: {}.").format(arg_k8ci_id) self.result['msg'] = ("Cannot find k8ci id: {}.").format(arg_k8ci_id)
self.amodule.fail_json(**self.result) self.amodule.fail_json(**self.result)
else: else:
self.result['failed'] = True self.result['failed'] = True
self.result['msg'] = ("Failed to get k8ci list HTTP code {}.").format(api_resp.status_code) self.result['msg'] = ("Failed to get k8ci list HTTP code {}.").format(api_resp.status_code)
@ -3736,3 +3734,699 @@ class DecortController(object):
self.result['msg'] = "group_delete() Group ID {} was deleted.".format(gr_id) self.result['msg'] = "group_delete() Group ID {} was deleted.".format(gr_id)
self.result['changed'] = True self.result['changed'] = True
return return
####################
### LB MANAGMENT ###
####################
def _lb_get_by_id(self,lb_id):
"""Helper function that locates LB by ID and returns LB facts. This function
expects that the ViNS exists (albeit in DELETED or DESTROYED state) and will return
0 LB ID if not found.
@param (int) vins_id: ID of the LB to find and return facts for.
@return: LB ID and a dictionary of LB facts as provided by LB/get API call.
"""
ret_lb_id = 0
ret_lb_dict = dict()
if not lb_id:
self.result['failed'] = True
self.result['msg'] = "lb_get_by_id(): zero LB ID specified."
self.amodule.fail_json(**self.result)
api_params = dict(lbId=lb_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/get", api_params)
if api_resp.status_code == 200:
ret_lb_id = lb_id
ret_lb_dict = json.loads(api_resp.content.decode('utf8'))
else:
self.result['warning'] = ("lb_get_by_id(): failed to get LB by ID {}. HTTP code {}, "
"response {}.").format(lb_id, api_resp.status_code, api_resp.reason)
return ret_lb_id, ret_lb_dict
def _rg_listlb(self,rg_id):
"""List all LB in the resource group
@param (int) rg_id: id onr resource group
"""
if not rg_id:
self.result['failed'] = True
self.result['msg'] = "_rg_listlb(): zero RG ID specified."
self.amodule.fail_json(**self.result)
api_params = dict(rgId=rg_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/listLb", api_params)
if api_resp.status_code == 200:
ret_rg_vins_list = json.loads(api_resp.content.decode('utf8'))
else:
self.result['warning'] = ("rg_listlb(): failed to get RG by ID {}. HTTP code {}, "
"response {}.").format(rg_id, api_resp.status_code, api_resp.reason)
return []
return ret_rg_vins_list
def lb_find(self,lb_id=0,lb_name="",rg_id=0):
"""Find specified LB.
@returns: LB ID and dictionary with LB facts.
"""
LB_INVALID_STATES = ["ENABLING", "DISABLING", "DELETING", "DELETED", "DESTROYING", "DESTROYED"]
ret_lb_id = 0
ret_lb_facts = None
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_find")
if lb_id > 0:
ret_lb_id, ret_lb_facts = self._lb_get_by_id(lb_id)
if not ret_lb_id:
self.result['failed'] = True
self.result['msg'] = "lb_find(): cannot find LB by ID {}.".format(lb_id)
self.amodule.fail_json(**self.result)
if not self.amodule.check_mode or ret_lb_facts['status'] not in LB_INVALID_STATES:
return ret_lb_id, ret_lb_facts
else:
return 0, None
elif lb_name != "":
if rg_id > 0:
list_lb = self._rg_listlb(rg_id)
for lb in list_lb:
if lb['name'] == lb_name:
ret_lb_id, ret_lb_facts = self._lb_get_by_id(lb['id'])
if not self.amodule.check_mode or ret_lb_facts['status'] not in LB_INVALID_STATES:
return ret_lb_id, ret_lb_facts
else:
return 0, None
else:
self.result['failed'] = True
self.result['msg'] = ("vins_lb(): cannot find LB by name '{}' "
"when no account ID or RG ID is specified.").format(lb_name)
self.amodule.fail_json(**self.result)
else:
self.result['failed'] = True
self.result['msg'] = "vins_find(): cannot find LB by zero ID and empty name."
self.amodule.fail_json(**self.result)
return 0, None
def lb_provision(self,lb_name,rg_id,vins_id,ext_net_id,annotation,start=True):
"""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.
Note, that when creating ViNS at account level, default location under DECORT controller
will be selected automatically.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_provision")
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = ("vins_lb() in check mode: provision LB name '{}' was "
"requested in RG with id: {}.").format(lb_name,rg_id)
return 0
if lb_name == "":
self.result['failed'] = True
self.result['msg'] = "lb_provision(): LB name cannot be empty."
self.amodule.fail_json(**self.result)
api_url = "/restmachine/cloudapi/lb/create"
api_params = dict(
name=lb_name,
rgId=rg_id,
extnetId=ext_net_id,
vinsId=vins_id,
start=start,
decs=annotation
)
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.
self.result['failed'] = False
self.result['changed'] = True
ret_lb_id = int(api_resp.content.decode('utf8'))
return ret_lb_id
def lb_delete(self,lb_id,permanently=False):
"""Deletes specified LB.
@param (int) lb_id: integer value that identifies the ViNS to be deleted.
@param (bool) permanently: a bool that tells if deletion should be permanent. If False, the LB will be
marked as DELETED and placed into a trash bin for predefined period of time (usually, a few days). Until
this period passes this LB can be restored by calling the corresponding 'restore' method.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_delete")
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = "lb_delete() in check mode: delete ViNS ID {} was requested.".format(lb_id)
return
api_params = dict(lbId=lb_id,
permanently=permanently)
self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/delete", 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
def lb_state(self, lb_dict, desired_state):
"""Change state for LB.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_state")
NOP_STATES_FOR_LB_CHANGE = ["MODELED", "DISABLING", "ENABLING", "DELETING", "DELETED", "DESTROYING",
"DESTROYED"]
VALID_TARGET_STATES = ["enabled", "disabled","restart"]
VALID_TARGET_TSTATES = ["STARTED","STOPPED"]
if lb_dict['status'] in NOP_STATES_FOR_LB_CHANGE:
self.result['failed'] = False
self.result['msg'] = ("lb_state(): no state change possible for LB ID {} "
"in its current state '{}'.").format(lb_dict['id'], lb_dict['status'])
return
if desired_state not in VALID_TARGET_STATES:
self.result['failed'] = False
self.result['warning'] = ("lb_state(): unrecognized desired state '{}' requested "
"for LB ID {}. No LB state change will be done.").format(desired_state,
lb_dict['id'])
return
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = ("lb_state() in check mode: setting state of LB ID {}, name '{}' to "
"'{}' was requested.").format(lb_dict['id'], lb_dict['name'],
desired_state)
return
state_api = ""
api_params = dict(lbId=lb_dict['id'])
expected_state = ""
if lb_dict['status'] in ["CREATED", "ENABLED"]:
if desired_state == 'disabled':
state_api = "/restmachine/cloudapi/lb/disable"
expected_state = "DISABLED"
if lb_dict['techStatus'] == "STARTED":
if desired_state == 'stopped':
state_api = "/restmachine/cloudapi/lb/stop"
if desired_state == 'restart':
state_api = "/restmachine/cloudapi/lb/restart"
elif lb_dict['techStatus'] == "STOPPED":
if desired_state == 'started':
state_api = "/restmachine/cloudapi/lb/start"
elif lb_dict['status'] == "DISABLED" and desired_state == 'enabled':
state_api = "/restmachine/cloudapi/lb/enable"
expected_state = "ENABLED"
if state_api != "":
self.decort_api_call(requests.post, state_api, 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
lb_dict['status'] = expected_state
else:
self.result['failed'] = False
self.result['msg'] = ("lb_state(): no state change required for LB ID {} from current "
"state '{}' to desired state '{}'.").format(lb_dict['id'],
lb_dict['status'],
desired_state)
return
def lb_restore(self, lb_id):
"""Restores previously deleted LB identified by its ID.
@param lb_id: ID of the LB to restore.
@returns: nothing on success. On error this method will abort module execution.
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_restore")
if self.amodule.check_mode:
self.result['failed'] = False
self.result['msg'] = "lb_restore() in check mode: restore LB ID {} was requested.".format(lb_id)
return
api_params = dict(lbId=lb_id)
self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/restore", 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
def lb_update_backends(self,lb_backends,mod_backends,mod_servers):
"""
backends
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_update_backends")
if mod_backends:
backs_out = [rec['name'] for rec in mod_backends]
else:
backs_out=""
backs_in = [rec['name'] for rec in lb_backends]
del_backs = set(backs_in).difference(backs_out)
add_becks = set(backs_out).difference(backs_in)
upd_becks = set(backs_in).intersection(backs_out)
for item in del_backs:
#need delete frontend
api_params = dict(lbId=self.lb_id,backendName = item)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendDelete", api_params)
self.result['changed'] = True
for item in add_becks:
backend, = list(filter(lambda i: i['name'] == item,mod_backends))
api_params = dict(
lbId=self.lb_id,
backendName = backend['name'],
algorithm = backend['algorithm'] if "algorithm" in backend else None,
**backend['default_settings'] if "default_settings" in backend else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendCreate", api_params)
self.result['changed'] = True
for item in upd_becks.union(add_becks):
backend, = list(filter(lambda i: i['name'] == item,lb_backends))
mod_backend, = list(filter(lambda i: i['name'] == item,mod_backends))
servers_in = [rec['name'] for rec in backend['servers']]
servers_out = []
#oO rework
if mod_servers:
for serv in mod_servers:
for bend in serv['backends']:
if bend['name'] == item:
servers_out.append(serv['name'])
del_srv = set(servers_in).difference(servers_out)
add_srv = set(servers_out).difference(servers_in)
upd_srv = set(servers_in).intersection(servers_out)
del backend['serverDefaultSettings']['guid']
if "default_settings" not in mod_backend:
mod_backend["default_settings"] = self.default_settings
if "algorithm" not in mod_backend:
mod_backend["algorithm"] = self.default_alg
if backend['serverDefaultSettings'] != mod_backend["default_settings"] or\
mod_backend["algorithm"] != backend['algorithm']:
api_params = dict(
lbId=self.lb_id,
backendName = item,
algorithm = mod_backend['algorithm'],
**mod_backend['default_settings'] if "default_settings" in mod_backend else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendUpdate", api_params)
self.result['changed'] = True
for srv in del_srv:
api_params = dict(lbId=self.lb_id,backendName = item,serverName=srv)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerDelete", api_params)
self.result['changed'] = True
for srv in add_srv:
server, = list(filter(lambda i: i['name'] == srv,mod_servers))
back, = list(filter(lambda i: i['name'] == item,server['backends']))
api_params = dict(
lbId=self.lb_id,
backendName = item,
serverName = server['name'],
address = server['address'],
port = back['port'],
check = server['check'] if "check" in server else None,
**server['server_settings'] if "server_settings" in server else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerAdd", api_params)
self.result['changed'] = True
for srv in upd_srv:
mod_server, = list(filter(lambda i: i['name'] == srv,mod_servers))
mod_server_back, = list(filter(lambda i: i['name'] == item,mod_server['backends']))
server, = list(filter(lambda i: i['name'] == srv, backend['servers']))
del server['serverSettings']['guid']
if "server_settings" not in mod_server_back:
mod_server_back['server_settings'] = self.default_settings
if "check" not in mod_server:
mod_server['check'] = self.default_server_check
if (mod_server['address'] != server['address'] or\
server['check']!=mod_server["check"]) or\
mod_server_back['server_settings'] != server['serverSettings']:
api_params = dict(
lbId=self.lb_id,
backendName = item,
serverName = mod_server['name'],
address = mod_server['address'],
port = mod_server_back['port'],
check = mod_server_back['check'] if "check" in mod_server_back else None,
**mod_server_back['server_settings'] if "server_settings" in mod_server_back else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerUpdate", api_params)
self.result['changed'] = True
return
def lb_update_frontends(self,lb_frontends,mod_frontends):
"""
frontends
"""
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "lb_update_frontends")
if mod_frontends:
front_out = [rec['name'] for rec in mod_frontends]
else:
front_out=""
front_in = [rec['name'] for rec in lb_frontends]
del_front = set(front_in).difference(front_out)
add_front = set(front_out).difference(front_in)
upd_front = set(front_in).intersection(front_out)
for front in del_front:
delete_front, = list(filter(lambda i: i['name'] == front,lb_frontends))
api_params = dict(
lbId=self.lb_id,
frontendName=delete_front['name'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendDelete", api_params)
self.result['changed'] = True
for front in add_front:
create_front, = list(filter(lambda i: i['name'] == front,mod_frontends))
api_params = dict(
lbId=self.lb_id,
frontendName=create_front['name'],
backendName=create_front['backend'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendCreate", api_params)
self.result['changed'] = True
if "bindings" in create_front:
for bind in create_front['bindings']:
self._lb_bind_frontend(
create_front['name'],
bind['name'],
bind['address'] if "address" in bind else None,
bind['port'] if "port" in bind else None
)
for front in upd_front:
update_front, = list(filter(lambda i: i['name'] == front,mod_frontends))
lb_front, = list(filter(lambda i: i['name'] == front,lb_frontends))
mod_bind = [rec['name'] for rec in update_front['bindings']]
lb_bind = [rec['name'] for rec in lb_front['bindings']]
del_bind_list = set(lb_bind).difference(mod_bind)
add_bind_list = set(mod_bind).difference(lb_bind)
upd_bind_list = set(lb_bind).intersection(mod_bind)
for bind_name in del_bind_list:
del_bind, = list(filter(lambda i: i['name'] == bind_name,lb_front['bindings']))
api_params = dict(
lbId=self.lb_id,
frontendName=update_front['name'],
bindingName=del_bind['name'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendBindDelete", api_params)
self.result['changed'] = True
for bind_name in add_bind_list:
add_bind, = list(filter(lambda i: i['name'] == bind_name,update_front['bindings']))
self._lb_bind_frontend(
update_front['name'],
add_bind['name'],
add_bind['address'] if "address" in add_bind else None,
add_bind['port'] if "port" in add_bind else None
)
for bind_name in upd_bind_list:
lb_act_bind, = list(filter(lambda i: i['name'] == bind_name,lb_front['bindings']))
mod_act_bind, = list(filter(lambda i: i['name'] == bind_name,update_front['bindings']))
del lb_act_bind['guid']
if lb_act_bind != mod_act_bind:
self._lb_bind_frontend(
update_front['name'],
mod_act_bind['name'],
mod_act_bind['address'] if "address" in mod_act_bind else None,
mod_act_bind['port'] if "port" in mod_act_bind else None,
update=True
)
return
def _lb_bind_frontend(self,front_name,bind_name,bind_addr=None,bind_port=None,update=False):
api_params = dict(
lbId=self.lb_id,
frontendName=front_name,
bindingName=bind_name,
bindingAddress=bind_addr,
bindingPort=bind_port,
)
if update == True:
api_url = "/restmachine/cloudapi/lb/frontendBindingUpdate"
else:
api_url = "/restmachine/cloudapi/lb/frontendBind"
api_resp = self.decort_api_call(requests.post, api_url, api_params)
self.result['changed'] = True
def lb_update(self,lb_backends=[],lb_frontends=[],mod_backends=[],mod_servers=[],mod_frontends=[]):
#lists from module and cloud
mod_backs_list = [back['name'] for back in mod_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)
add_back_list = set(mod_backs_list).difference(lb_backs_list)
upd_back_list = set(lb_backs_list).intersection(mod_backs_list)
#FE
mod_front_list = [front['name'] for front in mod_frontends]
lb_front_list = [front['name'] for front in lb_frontends]
if del_list_backs:
self._lb_delete_backends(
del_list_backs,
lb_frontends
)
if add_back_list:
self._lb_create_backends(
add_back_list,
mod_backends,
mod_servers
)
if upd_back_list:
self._lb_update_backends(
upd_back_list,
lb_backends,
mod_backends,
mod_servers
)
del_list_fronts = set(lb_front_list).difference(mod_front_list)
add_list_fronts = set(mod_front_list).difference(lb_front_list)
upd_front_list = set(lb_front_list).intersection(mod_front_list)
if del_list_fronts:
self._lb_delete_fronts(del_list_fronts)
if add_list_fronts:
self._lb_add_fronts(add_list_fronts,mod_frontends)
if upd_front_list:
self._lb_update_fronts(upd_front_list,lb_frontends,mod_frontends)
return
def _lb_delete_backends(self,back_list,lb_fronts):
#delete frontends with that backend
for back in back_list:
fronts = list(filter(lambda i: i['backend'] == back,lb_fronts))
if fronts:
self._lb_delete_fronts(fronts)
api_params = dict(
lbId=self.lb_id,
backendName = back
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendDelete", api_params)
self.result['changed'] = True
return
def _lb_delete_fronts(self,d_fronts):
for front in d_fronts:
api_params = dict(
lbId=self.lb_id,
frontendName=front['name'] if "name" in front else front,
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendDelete", api_params)
#del from cloud dict
if type(front)==dict:
del self.lb_facts['frontends'][front['name']]
self.result['changed'] = True
return
def _lb_add_fronts(self,front_list,mod_fronts):
for front in front_list:
add_front, = list(filter(lambda i: i['name'] == front,mod_fronts))
api_params = dict(
lbId=self.lb_id,
frontendName=add_front['name'],
backendName=add_front['backend'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendCreate", api_params)
for bind in add_front['bindings']:
self._lb_bind_frontend(
add_front['name'],
bind['name'],
bind['address']if "address" in bind else None,
bind['port'] if "port" in bind else None,
)
return
def _lb_create_backends(self,back_list,mod_backs,mod_serv):
'''
Create backends and add servers to them
'''
for back in back_list:
backend, = list(filter(lambda i: i['name'] == back,mod_backs))
api_params = dict(
lbId=self.lb_id,
backendName = back,
algorithm = backend['algorithm'] if "algorithm" in backend else None,
**backend['default_settings'] if "default_settings" in backend else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendCreate", api_params)
for server in mod_serv:
try:
srv_back, = list(filter(lambda i: i['name'] == back,server['backends']))
except:
continue
api_params = dict(
lbId=self.lb_id,
backendName = back,
serverName = server['name'],
address = server['address'],
port = srv_back['port'],
check = srv_back['check'] if "check" in srv_back else None,
**srv_back['server_settings'] if "server_settings" in srv_back else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerAdd", api_params)
self.result['changed'] = True
return
def _lb_update_backends(self,back_list,lb_backs,mod_backs,mod_serv):
lb_backs = list(filter(lambda i: i['name'] in back_list,lb_backs))
#mod_back = list(filter(lambda i: i['name'] in back_list,mod_backs))
for back in lb_backs:
del back['serverDefaultSettings']['guid']
mod_back, = list(filter(lambda i: i['name']==back['name'],mod_backs))
#mod_servers = list(filter(lambda i: i['name']==back['name'],mod_serv))
#raise Exception(mod_servers)
if "default_settings" not in mod_back:
mod_back["default_settings"] = self.default_settings
else:
for param,value in self.default_settings.items():
if param not in mod_back["default_settings"]:
mod_back["default_settings"].update(param,value)
if "algorithm" not in mod_back:
mod_back["algorithm"] = self.default_alg
if back['serverDefaultSettings'] != mod_back["default_settings"] or\
mod_back["algorithm"] != back['algorithm']:
api_params = dict(
lbId=self.lb_id,
backendName = back['name'],
algorithm = mod_back['algorithm'],
**mod_back['default_settings'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendUpdate", api_params)
self.result['changed'] = True
lb_servers_list = [srv['name'] for srv in back['servers']]
for server in mod_serv:
try:
mod_back, = list(filter(lambda i: i['name'] == back['name'],server['backends']))
except:
continue
if server['name'] not in lb_servers_list:
api_params = dict(
lbId=self.lb_id,
backendName = mod_back['name'],
serverName = server['name'],
address = server['address'],
port = mod_back['port'],
check = server['check'] if "check" in server else None,
**server['server_settings'] if "server_settings" in server else {},
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerAdd", api_params)
self.result['changed'] = True
else:
lb_server, = list(filter(lambda i: i['name'] == server['name'],back['servers']))
del lb_server['serverSettings']['guid']
if "server_settings" not in mod_back:
mod_back['server_settings'] = self.default_settings
else:
for param,value in self.default_settings.items():
if param not in mod_back["server_settings"]:
mod_back["server_settings"].update(param,value)
if "check" not in mod_back:
mod_back['check'] = self.default_server_check
if (server['address'] != lb_server['address'] or\
lb_server['check']!=mod_back['check']) or\
mod_back['server_settings'] != lb_server['serverSettings']:
api_params = dict(
lbId=self.lb_id,
backendName = mod_back['name'],
serverName = server['name'],
address = server['address'],
port = mod_back['port'],
check = mod_back['check'],
**mod_back['server_settings'],
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerUpdate", api_params)
self.result['changed'] = True
lb_servers_list.remove(server['name'])
for server in lb_servers_list:
api_params = dict(lbId=self.lb_id,backendName = back['name'],serverName=server)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/backendServerDelete", api_params)
self.result['changed'] = True
return
def _lb_update_fronts(self,upd_front_list,lb_frontends,mod_frontends):
for front in upd_front_list:
mod_front, = list(filter(lambda i: i['name'] == front,mod_frontends))
lb_front, = list(filter(lambda i: i['name'] == front,lb_frontends))
lb_binds_list = [bind['name'] for bind in lb_front['bindings']]
for bind in mod_front['bindings']:
if bind['name'] not in lb_binds_list:
pass
self._lb_bind_frontend(
front,
bind['name'],
bind['address']if "address" in bind else None,
bind['port'] if "port" in bind else None,
)
else:
lb_bind, = list(filter(lambda i: i['name'] == bind['name'],lb_front['bindings']))
del lb_bind['guid']
if dict(sorted(bind.items())) != dict(sorted(lb_bind.items())):
self._lb_bind_frontend(
front,
bind['name'],
bind['address']if "address" in bind else None,
bind['port'] if "port" in bind else None,
update=True,
)
lb_binds_list.remove(bind['name'])
for lb_bind in lb_binds_list:
api_params = dict(
lbId=self.lb_id,
frontendName=front,
bindingName=lb_bind,
)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/lb/frontendBindDelete", api_params)
self.result['changed'] = True
return

Loading…
Cancel
Save