Optimizing PFW management workflows

master
Sergey Shubin svs1370 5 years ago
parent c870989ed7
commit c7a3b5d6b2

@ -32,7 +32,7 @@ requirements:
- PyJWT module - PyJWT module
- requests module - requests module
- decort_utils utility library (module) - decort_utils utility library (module)
- DECORT cloud platform version 3.4.0 or higher - DECORT cloud platform version 3.4.2 or higher
options: options:
app_id: app_id:
description: description:

@ -182,7 +182,7 @@ from ansible.module_utils.basic import env_fallback
from ansible.module_utils.decort_utils import * from ansible.module_utils.decort_utils import *
def decort_pfw_package_facts(pfw_facts, check_mode=False): def decort_pfw_package_facts(comp_id, vins_id, pfw_facts, check_mode=False):
"""Package a dictionary of PFW rules facts according to the decort_pfw module specification. """Package a dictionary of PFW rules facts according to the decort_pfw module specification.
This dictionary will be returned to the upstream Ansible engine at the completion of This dictionary will be returned to the upstream Ansible engine at the completion of
the module run. the module run.
@ -191,11 +191,10 @@ def decort_pfw_package_facts(pfw_facts, check_mode=False):
@param (bool) check_mode: boolean that tells if this Ansible module is run in check mode @param (bool) check_mode: boolean that tells if this Ansible module is run in check mode
""" """
ret_dict = dict(id=0, ret_dict = dict(state="CHECK_MODE",
name="none",
state="CHECK_MODE",
compute_id=0, compute_id=0,
vins_id=0, vins_id=0,
rules=[],
) )
if check_mode: if check_mode:
@ -207,7 +206,14 @@ def decort_pfw_package_facts(pfw_facts, check_mode=False):
ret_dict['state'] = "ABSENT" ret_dict['state'] = "ABSENT"
return ret_dict return ret_dict
ret_dict['compute_id'] = pfw_facts['compute_id'] ret_dict['compute_id'] = comp_id
ret_dict['vins_id'] = vins_id
if len(pfw_facts) != 0:
ret_dict['state'] = 'PRESENT'
ret_dict['rules'] = pfw_facts
else:
ret_dict['state'] = 'ABSENT'
return ret_dict return ret_dict
@ -316,7 +322,7 @@ def main():
amodule.fail_json(**decon.result) amodule.fail_json(**decon.result)
else: else:
# prepare PFW facts to be returned as part of decon.result and then call exit_json(...) # prepare PFW facts to be returned as part of decon.result and then call exit_json(...)
decon.result['facts'] = decort_pfw_package_facts(pfw_facts, amodule.check_mode) decon.result['facts'] = decort_pfw_package_facts(comp_facts['id'], vins_facts['id'], pfw_facts, amodule.check_mode)
amodule.exit_json(**decon.result) amodule.exit_json(**decon.result)

@ -2419,6 +2419,24 @@ class DecortController(object):
# #
############################## ##############################
def _pfw_get(self, comp_id, vins_id):
"""Convenience method to get current PFW rules for the specified compute ID.
"""
api_params = dict(vinsId=vins_id)
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/vins/natRuleList", api_params)
all_rules = json.loads(api_resp.content.decode('utf8'))
if comp_id == 0:
# no filtering by compute ID, return rules as is
return all_rules
filtered_rules = []
for runner in all_rules:
if runner['vmId'] == comp_id:
filtered_rules.append(runner)
return filtered_rules
def pfw_configure(self, comp_facts, vins_facts, new_rules=None): def pfw_configure(self, comp_facts, vins_facts, new_rules=None):
"""Manage port forwarding rules for Compute in a smart way. The method will try to match existing """Manage port forwarding rules for Compute in a smart way. The method will try to match existing
rules against the new rules set and calculate the delta settings to apply to the corresponding rules against the new rules set and calculate the delta settings to apply to the corresponding
@ -2430,6 +2448,9 @@ class DecortController(object):
to which PFW rules set will be applied. to which PFW rules set will be applied.
@param (list of dicts) new_rules: new PFW rules set. If None is passed, remove all existing @param (list of dicts) new_rules: new PFW rules set. If None is passed, remove all existing
PFW rules for the Compute. PFW rules for the Compute.
@returns: list of dictionaries with PFW rules as returned by .../vins/natRuleList on success,
None on error.
""" """
# At the entry to this method we assume that initial validations are already passed, namely: # At the entry to this method we assume that initial validations are already passed, namely:
@ -2450,11 +2471,14 @@ class DecortController(object):
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "pfw_configure") self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "pfw_configure")
ret_rules = []
if self.amodule.check_mode: if self.amodule.check_mode:
self.result['failed'] = False self.result['failed'] = False
self.result['msg'] = ("pfw_configure() in check mode: port forwards configuration requested " self.result['msg'] = ("pfw_configure() in check mode: port forwards configuration requested "
"for Compute ID {} / ViNS ID {}").format(comp_facts['id'], vins_facts['id']) "for Compute ID {} / ViNS ID {}").format(comp_facts['id'], vins_facts['id'])
return None ret_rules = self._pfw_get(comp_facts['id'], vins_facts['id'])
return ret_rules
iface_ipaddr = "" # keep IP address associated with Compute's connection to this ViNS - need this for natRuleDel API iface_ipaddr = "" # keep IP address associated with Compute's connection to this ViNS - need this for natRuleDel API
for iface in comp_facts['interfaces']: for iface in comp_facts['interfaces']:
@ -2464,7 +2488,7 @@ class DecortController(object):
else: else:
decon.result['failed'] = True decon.result['failed'] = True
decon.result['msg'] = "Compute ID {} is not connected to ViNS ID {}.".format(comp_facts['id'], vins_facts['id']) decon.result['msg'] = "Compute ID {} is not connected to ViNS ID {}.".format(comp_facts['id'], vins_facts['id'])
return None return ret_rules
existing_rules = [] existing_rules = []
for runner in vins_facts['vnfs']['NAT']['config']['rules']: for runner in vins_facts['vnfs']['NAT']['config']['rules']:
@ -2475,7 +2499,7 @@ class DecortController(object):
self.result['failed'] = False self.result['failed'] = False
self.result['warning'] = ("pfw_configure(): both existing and new port forwarding rule lists " self.result['warning'] = ("pfw_configure(): both existing and new port forwarding rule lists "
"for Compute ID {} are empty - nothing to do.").format(comp_facts['id']) "for Compute ID {} are empty - nothing to do.").format(comp_facts['id'])
return None return ret_rules
if new_rules == None or len(new_rules) == 0: if new_rules == None or len(new_rules) == 0:
# delete all existing rules for this Compute # delete all existing rules for this Compute
@ -2483,7 +2507,7 @@ class DecortController(object):
ruleId=-1) ruleId=-1)
self.decort_api_call(requests.post, "/restmachine/cloudapi/vins/natRuleDel", api_params) self.decort_api_call(requests.post, "/restmachine/cloudapi/vins/natRuleDel", api_params)
self.result['changed'] = True self.result['changed'] = True
return None return ret_rules
# #
# delta_list will be a list of dictionaries that describe _changes_ to the port forwarding rules # delta_list will be a list of dictionaries that describe _changes_ to the port forwarding rules
@ -2501,6 +2525,14 @@ class DecortController(object):
for rule in new_rules: for rule in new_rules:
rule['action'] = 'add' rule['action'] = 'add'
rule_port_end = rule.get('public_port_end', rule['public_port_start']) rule_port_end = rule.get('public_port_end', rule['public_port_start'])
if rule_port_end > rule['public_port_start']:
# This is a ranged rule, i.e. when range of public ports maps to an equally
# sized range of local ports.
# For such case we have to make sure that the local port equals public
# port (this check & adjustment will be made by vnf_nat.add method anyway, but
# if we adjust here, we can avoid unnecessary rule del / add iteration in the
# module run, thus saving execution time)
rule['local_port'] = rule['public_port_start']
for runner in existing_rules: for runner in existing_rules:
if (runner['publicPortStart'] == rule['public_port_start'] and if (runner['publicPortStart'] == rule['public_port_start'] and
runner['publicPortEnd'] == rule_port_end and runner['publicPortEnd'] == rule_port_end and
@ -2536,7 +2568,8 @@ class DecortController(object):
self.result['failed'] = False self.result['failed'] = False
self.result['warning'] = ("pfw_configure() no difference between current and new PFW rules " self.result['warning'] = ("pfw_configure() no difference between current and new PFW rules "
"found. No change applied to Compute ID {}.").format(comp_facts['id']) "found. No change applied to Compute ID {}.").format(comp_facts['id'])
return ret_rules = self._pfw_get(comp_facts['id'], vins_facts['id'])
return ret_rules
# now delta_list contains a list of enriched rule dictionaries with extra key 'action', which # now delta_list contains a list of enriched rule dictionaries with extra key 'action', which
# tells what kind of action is expected on this rule - 'add' or 'del' # tells what kind of action is expected on this rule - 'add' or 'del'
@ -2567,4 +2600,5 @@ class DecortController(object):
self.result['failed'] = False self.result['failed'] = False
return ret_rules = self._pfw_get(comp_facts['id'], vins_facts['id'])
return ret_rules
Loading…
Cancel
Save