Merge branch 'feature/decort_lb'

rc-5.2.3
Alex_geth 2 years ago
commit 82eef4492d

@ -114,10 +114,10 @@ class decort_k8s(DecortController):
return ret_dict
def nop(self):
"""No operation (NOP) handler for Compute management by decort_kvmvm module.
"""No operation (NOP) handler for k8s cluster management by decort_k8s 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 Compute state.
the actual k8s cluster state.
"""
self.result['failed'] = False
self.result['changed'] = False

@ -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()

@ -242,17 +242,185 @@ facts:
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
import paramiko
from ansible.module_utils.decort_utils import *
class decort_vins(DecortController):
def __init__(self,arg_amodule):
super(decort_vins, self).__init__(arg_amodule)
def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
self.vins_id = 0
self.vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
vins_facts = None # will hold ViNS facts
validated_rg_id = 0
rg_facts = None # will hold RG facts
validated_acc_id = 0
acc_facts = None # will hold Account facts
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.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']
elif arg_amodule.params['rg_id']:
# expect ViNS @ RG level in the RG with specified ID
self.vins_level = "RG"
# 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
arg_amodule.params['rg_id'], arg_rg_name="")
# This call to vins_find may return vins_id=0 if no ViNS found
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
account_id=0,
rg_id=arg_amodule.params['rg_id'],
rg_facts=rg_facts,
check_state=False)
# TODO: add checks and setup ViNS presence flags accordingly
pass
elif arg_amodule.params['account_id'] or arg_amodule.params['account_name'] != "":
# Specified account must be present and accessible by the user, otherwise abort the module
validated_acc_id, acc_facts = self.account_find(arg_amodule.params['account_name'], arg_amodule.params['account_id'])
if not validated_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)
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
validated_rg_id, rg_facts = self.rg_find(validated_acc_id, 0, arg_amodule.params['rg_name'])
if (not validated_rg_id or
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)
# 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
rg_id=validated_rg_id,
rg_facts=rg_facts,
check_state=False)
self.vins_level = "RG"
# TODO: add checks and setup ViNS presence flags accordingly
else: # At this point we know for sure that rg_name="" and rg_id=0
# So we expect ViNS @ account level
# This call to vins_find may return vins_id=0 if no ViNS found
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
account_id=validated_acc_id,
rg_id=0,
rg_facts=rg_facts,
check_state=False)
self.vins_level = "ACC"
# TODO: add checks and setup ViNS presence flags accordingly
else:
# 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 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)
return
self.rg_id = validated_rg_id
self.acc_id = validated_acc_id
return
def create(self):
self.vins_id = self.vins_provision(self.amodule.params['vins_name'],
self.acc_id, self.rg_id,
self.amodule.params['ipcidr'],
self.amodule.params['ext_net_id'], self.amodule.params['ext_ip_addr'],
self.amodule.params['annotation'])
if self.amodule.params['mgmtaddr'] or self.amodule.params['connect_to']:
_, self.vins_facts = self.vins_find(self.vins_id)
if self.amodule.params['connect_to']:
self.vins_update_ifaces(self.vins_facts,self.amodule.params['connect_to'],)
if self.amodule.params['mgmtaddr']:
self.vins_update_mgmt(self.vins_facts,self.amodule.params['mgmtaddr'])
return
def action(self,d_state='',restore=False):
if restore == True:
self.vins_restore(arg_vins_id=self.vins_id)
self.vins_state(self.vins_facts, 'enabled')
self.vins_facts['status'] = "ENABLED"
self.vins_facts['VNFDev']['techStatus'] = "STARTED"
self.vins_update_extnet(self.vins_facts,
self.amodule.params['ext_net_id'],
self.amodule.params['ext_ip_addr'],
)
if d_state == 'enabled' and self.vins_facts['status'] == "DISABLED":
self.vins_state(self.vins_facts, d_state)
self.vins_facts['status'] = "ENABLED"
self.vins_facts['VNFDev']['techStatus'] = "STARTED"
d_state = ''
if self.vins_facts['status'] == "ENABLED" and self.vins_facts['VNFDev']['techStatus'] == "STARTED":
self.vins_update_ifaces(self.vins_facts,
self.amodule.params['connect_to'],
)
if self.result['changed']:
_, self.vins_facts = self.vins_find(self.vins_id)
self.vins_update_mgmt(self.vins_facts,
self.amodule.params['mgmtaddr'],
)
if d_state != '':
self.vins_state(self.vins_facts, d_state)
return
def delete(self):
self.vins_delete(self.vins_id, permanently=True)
self.vins_facts['status'] = 'DESTROYED'
return
def nop(self):
"""No operation (NOP) handler for ViNS management by decort_vins 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 ViNS state.
"""
self.result['failed'] = False
self.result['changed'] = False
if self.vins_id:
self.result['msg'] = ("No state change required for ViNS ID {} because of its "
"current status '{}'.").format(self.vins_id, self.vins_facts['status'])
else:
self.result['msg'] = ("No state change to '{}' can be done for "
"non-existent ViNS 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 ViNS ID {} in the "
"current status '{}'").format(self.vins_id,
self.amodule.params['state'],
self.vins_facts['status'])
else:
self.result['failed'] = True
self.result['changed'] = False
self.result['msg'] = ("Invalid target state '{}' requested for non-existent "
"ViNS name '{}'").format(self.amodule.params['state'],
self.amodule.params['vins_name'])
return
def package_facts(self, arg_check_mode=False):
"""Package a dictionary of ViNS facts according to the decort_vins module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of
the module run.
@param arg_vins_facts: dictionary with viNS facts as returned by API call to .../vins/get
@param arg_check_mode: boolean that tells if this Ansible module is run in check mode
"""
@ -265,21 +433,32 @@ def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
# in check mode return immediately with the default values
return ret_dict
if arg_vins_facts is None:
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'] = arg_vins_facts['id']
ret_dict['name'] = arg_vins_facts['name']
ret_dict['state'] = arg_vins_facts['status']
ret_dict['account_id'] = arg_vins_facts['accountId']
ret_dict['rg_id'] = arg_vins_facts['rgId']
ret_dict['int_net_addr'] = arg_vins_facts['network']
ret_dict['gid'] = arg_vins_facts['gid']
if arg_vins_facts['vnfs'].get('GW'):
gw_config = arg_vins_facts['vnfs']['GW']['config']
ret_dict['id'] = self.vins_facts['id']
ret_dict['name'] = self.vins_facts['name']
ret_dict['state'] = self.vins_facts['status']
ret_dict['account_id'] = self.vins_facts['accountId']
ret_dict['rg_id'] = self.vins_facts['rgId']
ret_dict['int_net_addr'] = self.vins_facts['network']
ret_dict['gid'] = self.vins_facts['gid']
custom_interfaces = list(filter(lambda i: i['type']=="CUSTOM",self.vins_facts['VNFDev']['interfaces']))
if custom_interfaces:
ret_dict['custom_net_addr'] = []
for runner in custom_interfaces:
ret_dict['custom_net_addr'].append(runner['ipAddress'])
mgmt_interfaces = list(filter(lambda i: i['listenSsh'] and i['name']!="ens9",self.vins_facts['VNFDev']['interfaces']))
if mgmt_interfaces:
ret_dict['ssh_ipaddr'] = []
for runner in mgmt_interfaces:
ret_dict['ssh_ipaddr'].append(runner['ipAddress'])
ret_dict['ssh_password'] = self.vins_facts['VNFDev']['config']['mgmt']['password']
ret_dict['ssh_port'] = 9022
if self.vins_facts['vnfs'].get('GW'):
gw_config = self.vins_facts['vnfs']['GW']['config']
ret_dict['ext_ip_addr'] = gw_config['ext_net_ip']
ret_dict['ext_net_id'] = gw_config['ext_net_id']
else:
@ -293,8 +472,8 @@ def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
return ret_dict
def decort_vins_parameters():
@staticmethod
def build_parameters():
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
by AnsibleModule utility class."""
@ -317,7 +496,7 @@ def decort_vins_parameters():
ext_net_id=dict(type='int', required=False, default=-1),
ext_ip_addr=dict(type='str', required=False, default=''),
ipcidr=dict(type='str', required=False, default=''),
mgmtaddr=dict(type='str',required=False, default=''),
mgmtaddr=dict(type='list',required=False, default=[]),
custom_config=dict(type='bool',required=False, default=False),
config_save=dict(type='bool',required=False, default=False),
connect_to=dict(type='list', default=[], required=False),
@ -356,7 +535,7 @@ def decort_vins_parameters():
# 5) report result to Ansible
def main():
module_parameters = decort_vins_parameters()
module_parameters = decort_vins.build_parameters()
amodule = AnsibleModule(argument_spec=module_parameters,
supports_check_mode=True,
@ -371,84 +550,7 @@ def main():
],
)
decon = DecortController(amodule)
vins_id = 0
vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
vins_facts = None # will hold ViNS facts
validated_rg_id = 0
rg_facts = None # will hold RG facts
validated_acc_id = 0
acc_facts = None # will hold Account facts
if 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
vins_id, vins_facts = decon.vins_find(amodule.params['vins_id'])
if not vins_id:
decon.result['failed'] = True
decon.result['msg'] = "Specified ViNS ID {} not found.".format(amodule.params['vins_id'])
decon.fail_json(**decon.result)
vins_level = "ID"
validated_acc_id = vins_facts['accountId']
validated_rg_id = vins_facts['rgId']
elif amodule.params['rg_id']:
# expect ViNS @ RG level in the RG with specified ID
vins_level = "RG"
# This call to rg_find will abort the module if no RG with such ID is present
validated_rg_id, rg_facts = decon.rg_find(0, # account ID set to 0 as we search for RG by RG ID
amodule.params['rg_id'], arg_rg_name="")
# This call to vins_find may return vins_id=0 if no ViNS found
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
account_id=0,
rg_id=amodule.params['rg_id'],
check_state=False)
# TODO: add checks and setup ViNS presence flags accordingly
pass
elif amodule.params['account_id'] or amodule.params['account_name'] != "":
# Specified account must be present and accessible by the user, otherwise abort the module
validated_acc_id, acc_facts = decon.account_find(amodule.params['account_name'], amodule.params['account_id'])
if not validated_acc_id:
decon.result['failed'] = True
decon.result['msg'] = ("Current user does not have access to the requested account "
"or non-existent account specified.")
decon.fail_json(**decon.result)
if 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
validated_rg_id, rg_facts = decon.rg_find(validated_acc_id, 0, amodule.params['rg_name'])
if (not validated_rg_id or
rg_facts['status'] in ["DESTROYING", "DESTROYED", "DELETING", "DELETED", "DISABLING", "ENABLING"]):
decon.result['failed'] = True
decon.result['msg'] = "RG name '{}' not found or has invalid state.".format(amodule.params['rg_name'])
decon.fail_json(**decon.result)
# This call to vins_find may return vins_id=0 if no ViNS with this name found under specified RG
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
account_id=0, # set to 0, as we are looking for ViNS under RG
rg_id=validated_rg_id,
check_state=False)
vins_level = "RG"
# TODO: add checks and setup ViNS presence flags accordingly
else: # At this point we know for sure that rg_name="" and rg_id=0
# So we expect ViNS @ account level
# This call to vins_find may return vins_id=0 if no ViNS found
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
account_id=validated_acc_id,
rg_id=0,
check_state=False)
vins_level = "ACC"
# TODO: add checks and setup ViNS presence flags accordingly
else:
# 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
decon.result['failed'] = True
if amodule.params['account_id'] == 0 and amodule.params['account_name'] == "":
decon.result['msg'] = "Cannot find ViNS by name when account name is empty and account ID is 0."
if amodule.params['rg_name'] == "":
# rg_name without account specified
decon.result['msg'] = "Cannot find ViNS by name when RG name is empty and RG ID is 0."
decon.fail_json(**decon.result)
decon = decort_vins(amodule)
#
# Initial validation of module arguments is complete
#
@ -465,127 +567,70 @@ def main():
# if cconfig_save is true, only config save without other updates
vins_should_exist = False
if vins_id:
if decon.vins_id:
vins_should_exist = True
if vins_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING"]:
if decon.vins_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING"]:
# error: nothing can be done to existing ViNS in the listed statii regardless of
# the requested state
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("No change can be done for existing ViNS ID {} because of its current "
"status '{}'").format(vins_id, vins_facts['status'])
elif vins_facts['status'] == "DISABLED":
"status '{}'").format(decon.vins_id, decon.vins_facts['status'])
elif decon.vins_facts['status'] == "DISABLED":
if amodule.params['state'] == 'absent':
decon.vins_delete(vins_id, permanently=True)
vins_facts['status'] = 'DESTROYED'
decon.delete()
vins_should_exist = False
elif amodule.params['state'] in ('present', 'disabled'):
# update ViNS, leave in disabled state
decon.vins_update(vins_facts,
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
decon.action()
elif amodule.params['state'] == 'enabled':
# update ViNS and enable
decon.vins_update(vins_facts,
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
decon.vins_state(vins_facts, 'enabled')
elif vins_facts['status'] in ["CREATED", "ENABLED"]:
decon.action('enabled')
elif decon.vins_facts['status'] in ["CREATED", "ENABLED"]:
if amodule.params['state'] == 'absent':
decon.vins_delete(vins_id, permanently=True)
vins_facts['status'] = 'DESTROYED'
decon.delete()
vins_should_exist = False
elif amodule.params['state'] in ('present', 'enabled'):
# update ViNS
decon.vins_update(vins_facts,
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
)
decon.vins_update_mgmt(
vins_facts,
amodule.params['mgmtaddr'],
)
decon.vins_update_ifaces(
vins_facts,
amodule.params['connect_to'],
)
decon.action()
elif amodule.params['state'] == 'disabled':
# disable and update ViNS
decon.vins_state(vins_facts, 'disabled')
decon.vins_update(vins_facts,
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
elif vins_facts['status'] == "DELETED":
decon.action('disabled')
elif decon.vins_facts['status'] == "DELETED":
if amodule.params['state'] in ['present', 'enabled']:
# restore and enable
decon.vins_restore(arg_vins_id=vins_id)
decon.vins_state(vins_facts, 'enabled')
decon.action(restore=True)
vins_should_exist = True
elif amodule.params['state'] == 'absent':
# destroy permanently
decon.vins_delete(vins_id, permanently=True)
vins_facts['status'] = 'DESTROYED'
decon.delete()
vins_should_exist = False
elif amodule.params['state'] == 'disabled':
# error
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("Invalid target state '{}' requested for ViNS ID {} in the "
"current status '{}'").format(vins_id,
amodule.params['state'],
vins_facts['status'])
decon.error()
vins_should_exist = False
elif vins_facts['status'] == "DESTROYED":
elif decon.vins_facts['status'] == "DESTROYED":
if amodule.params['state'] in ('present', 'enabled'):
# need to re-provision ViNS; some attributes may be changed, some stay the same.
# account and RG - stays the same
# vins_name - stays the same
# IPcidr - take from module arguments
# ext IP address - take from module arguments
# annotation - take from module arguments
vins_id = decon.vins_provision(vins_facts['name'],
validated_acc_id, validated_rg_id,
amodule.params['ipcidr'],
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
amodule.params['annotation'])
# need to re-provision ViNS;
decon.create()
vins_should_exist = True
elif amodule.params['state'] == 'absent':
# nop
decon.result['failed'] = False
decon.result['changed'] = False
decon.result['msg'] = ("No state change required for ViNS ID {} because of its "
"current status '{}'").format(vins_id,
vins_facts['status'])
decon.nop()
vins_should_exist = False
elif amodule.params['state'] == 'disabled':
# error
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("Invalid target state '{}' requested for ViNS ID {} in the "
"current status '{}'").format(vins_id,
amodule.params['state'],
vins_facts['status'])
decon.error()
else:
# Preexisting ViNS was not found.
vins_should_exist = False # we will change it back to True if ViNS is created or restored
# If requested state is 'absent' - nothing to do
if amodule.params['state'] == 'absent':
decon.result['failed'] = False
decon.result['changed'] = False
decon.result['msg'] = ("Nothing to do as target state 'absent' was requested for "
"non-existent ViNS name '{}'").format(amodule.params['vins_name'])
decon.nop()
elif amodule.params['state'] in ('present', 'enabled'):
decon.check_amodule_argument('vins_name')
# as we already have account ID and RG ID we can create ViNS and get vins_id on success
vins_id = decon.vins_provision(amodule.params['vins_name'],
validated_acc_id, validated_rg_id,
amodule.params['ipcidr'],
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
amodule.params['annotation'])
decon.create()
vins_should_exist = True
elif amodule.params['state'] == 'disabled':
decon.result['failed'] = True
decon.result['changed'] = False
decon.result['msg'] = ("Invalid target state '{}' requested for non-existent "
"ViNS name '{}'").format(amodule.params['state'],
amodule.params['vins_name'])
decon.error()
#
# conditional switch end - complete module run
#
@ -593,18 +638,9 @@ def main():
amodule.fail_json(**decon.result)
else:
# prepare ViNS facts to be returned as part of decon.result and then call exit_json(...)
if vins_should_exist:
if decon.result['changed']:
# If we arrive here, there is a good chance that the ViNS is present - get fresh ViNS
# facts from # the cloud by ViNS ID.
# Otherwise, ViNS facts from previous call (when the ViNS was still in existence) will
# be returned.
_, vins_facts = decon.vins_find(vins_id)
decon.result['facts'] = decort_vins_package_facts(vins_facts, amodule.check_mode)
# add password to facts if mgmtaddr is present
# need reworking
if amodule.params['mgmtaddr'] != "":
decon.result['facts'].update({'password': vins_facts['VNFDev']['config']['mgmt']['password']})
_, decon.vins_facts = decon.vins_find(decon.vins_id)
decon.result['facts'] = decon.package_facts(amodule.check_mode)
amodule.exit_json(**decon.result)

@ -31,7 +31,6 @@ Requirements:
- DECORT cloud platform version 3.6.1 or higher
"""
import copy
import json
import jwt
import netaddr
@ -1207,7 +1206,7 @@ class DecortController(object):
affinityLabel=label,)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityLabelSet", api_params)
if aff:
if len(aff[0])>0:
if len(aff)>0:
for rule in aff:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
@ -1217,7 +1216,7 @@ class DecortController(object):
policy=rule['policy'],)
self.decort_api_call(requests.post, "/restmachine/cloudapi/compute/affinityRuleAdd", api_params)
if aaff:
if len(aaff[0])>0:
if len(aaff)>0:
for rule in aaff:
api_params = dict(computeId=comp_dict['id'],
key=rule['key'],
@ -1975,7 +1974,7 @@ class DecortController(object):
if api_resp.status_code == 200:
locations = json.loads(api_resp.content.decode('utf8'))
if location_code == "" and locations:
ret_gid = locations[0]['gid']
ret_gid = locations['gid']
else:
for runner in locations:
if runner['locationCode'] == location_code:
@ -3298,7 +3297,7 @@ class DecortController(object):
self.result['failed'] = True
return
elif ret_info['status'] == "OK":
k8s_id = ret_info['result'][0]
k8s_id = ret_info['result']
self.result['changed'] = True
return k8s_id
else:
@ -3401,7 +3400,7 @@ class DecortController(object):
k8ci_id_present = True
break
if k8ci_id_present == False:
else:
self.result['failed'] = True
self.result['msg'] = ("Cannot find k8ci id: {}.").format(arg_k8ci_id)
self.amodule.fail_json(**self.result)
@ -3764,3 +3763,699 @@ class DecortController(object):
self.result['msg'] = "group_delete() Group ID {} was deleted.".format(gr_id)
self.result['changed'] = True
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