diff options
14 files changed, 1374 insertions, 1529 deletions
| diff --git a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py index a2a6e04..275aaf3 100644 --- a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py @@ -29,337 +29,241 @@ The arg spec for the vyos_ospfv2 module  class Ospfv2Args(object):  # pylint: disable=R0903      """The arg spec for the vyos_ospfv2 module      """ +      def __init__(self, **kwargs):          pass      argument_spec = { -        'config': { -            'options': { -                'auto_cost': { -                    'options': { -                        'reference_bandwidth': { -                            'type': 'int' -                        } -                    }, -                    'type': 'dict' +        "config": { +            "options": { +                "auto_cost": { +                    "options": {"reference_bandwidth": {"type": "int"}}, +                    "type": "dict",                  }, -                'default_information': { -                    'options': { -                        'originate': { -                            'options': { -                                'always': { -                                    'type': 'bool' -                                }, -                                'metric': { -                                    'type': 'int' -                                }, -                                'metric_type': { -                                    'type': 'int' -                                }, -                                'route_map': { -                                    'type': 'str' -                                } +                "default_information": { +                    "options": { +                        "originate": { +                            "options": { +                                "always": {"type": "bool"}, +                                "metric": {"type": "int"}, +                                "metric_type": {"type": "int"}, +                                "route_map": {"type": "str"},                              }, -                            'type': 'dict' +                            "type": "dict",                          }                      }, -                    'type': 'dict' -                }, -                'default_metric': { -                    'type': 'int' +                    "type": "dict",                  }, -                'distance': { -                    'options': { -                        'global': { -                            'type': 'int' -                        }, -                        'ospf': { -                            'options': { -                                'external': { -                                    'type': 'int' -                                }, -                                'inter_area': { -                                    'type': 'int' -                                }, -                                'intra_area': { -                                    'type': 'int' -                                } +                "default_metric": {"type": "int"}, +                "distance": { +                    "options": { +                        "global": {"type": "int"}, +                        "ospf": { +                            "options": { +                                "external": {"type": "int"}, +                                "inter_area": {"type": "int"}, +                                "intra_area": {"type": "int"},                              }, -                            'type': 'dict' -                        } +                            "type": "dict", +                        },                      }, -                    'type': 'dict' +                    "type": "dict",                  }, -                'log_adjacency_changes': { -                    'choices': ['detail'], -                    'type': 'str' +                "log_adjacency_changes": { +                    "choices": ["detail"], +                    "type": "str",                  }, -                'max_metric': { -                    'options': { -                        'router_lsa': { -                            'options': { -                                'administrative': { -                                    'type': 'bool' -                                }, -                                'on_shutdown': { -                                    'type': 'int' -                                }, -                                'on_startup': { -                                    'type': 'int' -                                } +                "max_metric": { +                    "options": { +                        "router_lsa": { +                            "options": { +                                "administrative": {"type": "bool"}, +                                "on_shutdown": {"type": "int"}, +                                "on_startup": {"type": "int"},                              }, -                            'type': 'dict' +                            "type": "dict",                          }                      }, -                    'type': 'dict' +                    "type": "dict",                  }, -                'mpls_te': { -                    'options': { -                        'enabled': { -                            'type': 'bool' -                        }, -                        'router_address': { -                            'type': 'str' -                        } +                "mpls_te": { +                    "options": { +                        "enabled": {"type": "bool"}, +                        "router_address": {"type": "str"},                      }, -                    'type': 'dict' +                    "type": "dict",                  }, -                'neighbor': { -                    'elements': 'dict', -                    'options': { -                        'neighbor_id': { -                            'type': 'str' -                        }, -                        'poll_interval': { -                            'type': 'int' -                        }, -                        'priority': { -                            'type': 'int' -                        } +                "neighbor": { +                    "elements": "dict", +                    "options": { +                        "neighbor_id": {"type": "str"}, +                        "poll_interval": {"type": "int"}, +                        "priority": {"type": "int"},                      }, -                    'type': 'list' +                    "type": "list",                  }, -                'areas': { -                    'elements': 'dict', -                    'options': { -                        'area_id': { -                            'type': 'str' -                        }, -                        'area_type': { -                            'options': { -                                'normal': { -                                    'type': 'bool' -                                }, -                                'nssa': { -                                    'options': { -                                        'default_cost': { -                                            'type': 'int' -                                        }, -                                        'no_summary': { -                                            'type': 'bool' +                "areas": { +                    "elements": "dict", +                    "options": { +                        "area_id": {"type": "str"}, +                        "area_type": { +                            "options": { +                                "normal": {"type": "bool"}, +                                "nssa": { +                                    "options": { +                                        "default_cost": {"type": "int"}, +                                        "no_summary": {"type": "bool"}, +                                        "set": {"type": "bool"}, +                                        "translate": { +                                            "choices": [ +                                                "always", +                                                "candidate", +                                                "never", +                                            ], +                                            "type": "str",                                          }, -                                        'set': { -                                            'type': 'bool' -                                        }, -                                        'translate': { -                                            'choices': -                                            ['always', 'candidate', 'never'], -                                            'type': -                                            'str' -                                        }                                      }, -                                    'type': 'dict' +                                    "type": "dict",                                  }, -                                'stub': { -                                    'options': { -                                        'default_cost': { -                                            'type': 'int' -                                        }, -                                        'no_summary': { -                                            'type': 'bool' -                                        }, -                                        'set': { -                                            'type': 'bool' -                                        } +                                "stub": { +                                    "options": { +                                        "default_cost": {"type": "int"}, +                                        "no_summary": {"type": "bool"}, +                                        "set": {"type": "bool"},                                      }, -                                    'type': 'dict' -                                } +                                    "type": "dict", +                                },                              }, -                            'type': 'dict' +                            "type": "dict",                          }, -                        'authentication': { -                            'choices': ['plaintext-password', 'md5'], -                            'type': 'str' +                        "authentication": { +                            "choices": ["plaintext-password", "md5"], +                            "type": "str",                          }, -                        'network': { -                            'elements': 'dict', -                            'options': { -                                'address': { -                                    'required': True, -                                    'type': 'str' -                                } +                        "network": { +                            "elements": "dict", +                            "options": { +                                "address": {"required": True, "type": "str"}                              }, -                            'type': 'list' +                            "type": "list",                          }, -                        'range': { -                            'elements': 'dict', -                            'options': { -                                'address': { -                                    'type': 'str' -                                }, -                                'cost': { -                                    'type': 'int' -                                }, -                                'not_advertise': { -                                    'type': 'bool' -                                }, -                                'substitute': { -                                    'type': 'str' -                                } +                        "range": { +                            "elements": "dict", +                            "options": { +                                "address": {"type": "str"}, +                                "cost": {"type": "int"}, +                                "not_advertise": {"type": "bool"}, +                                "substitute": {"type": "str"},                              }, -                            'type': 'list' +                            "type": "list",                          }, -                        'shortcut': { -                            'choices': ['default', 'disable', 'enable'], -                            'type': 'str' +                        "shortcut": { +                            "choices": ["default", "disable", "enable"], +                            "type": "str",                          }, -                        'virtual_link': { -                            'elements': 'dict', -                            'options': { -                                'address': { -                                    'type': 'str' -                                }, -                                'authentication': { -                                    'options': { -                                        'md5': { -                                            'elements': 'dict', -                                            'options': { -                                                'key_id': { -                                                    'type': 'int' -                                                }, -                                                'md5_key': { -                                                    'type': 'str' -                                                } +                        "virtual_link": { +                            "elements": "dict", +                            "options": { +                                "address": {"type": "str"}, +                                "authentication": { +                                    "options": { +                                        "md5": { +                                            "elements": "dict", +                                            "options": { +                                                "key_id": {"type": "int"}, +                                                "md5_key": {"type": "str"},                                              }, -                                            'type': 'list' +                                            "type": "list",                                          }, -                                        'plaintext_password': { -                                            'type': 'str' -                                        } +                                        "plaintext_password": {"type": "str"},                                      }, -                                    'type': 'dict' -                                }, -                                'dead_interval': { -                                    'type': 'int' -                                }, -                                'hello_interval': { -                                    'type': 'int' +                                    "type": "dict",                                  }, -                                'retransmit_interval': { -                                    'type': 'int' -                                }, -                                'transmit_delay': { -                                    'type': 'int' -                                } +                                "dead_interval": {"type": "int"}, +                                "hello_interval": {"type": "int"}, +                                "retransmit_interval": {"type": "int"}, +                                "transmit_delay": {"type": "int"},                              }, -                            'type': 'list' -                        } +                            "type": "list", +                        },                      }, -                    'type': 'list' +                    "type": "list",                  }, -                'parameters': { -                    'options': { -                        'abr_type': { -                            'choices': -                            ['cisco', 'ibm', 'shortcut', 'standard'], -                            'type': 'str' +                "parameters": { +                    "options": { +                        "abr_type": { +                            "choices": [ +                                "cisco", +                                "ibm", +                                "shortcut", +                                "standard", +                            ], +                            "type": "str",                          }, -                        'opaque_lsa': { -                            'type': 'bool' -                        }, -                        'rfc1583_compatibility': { -                            'type': 'bool' -                        }, -                        'router_id': { -                            'type': 'str' -                        } +                        "opaque_lsa": {"type": "bool"}, +                        "rfc1583_compatibility": {"type": "bool"}, +                        "router_id": {"type": "str"},                      }, -                    'type': 'dict' +                    "type": "dict",                  }, -                'passive_interface': { -                    'type': 'list' -                }, -                'passive_interface_exclude': { -                    'type': 'list' -                }, -                'redistribute': { -                    'elements': 'dict', -                    'options': { -                        'metric': { -                            'type': 'int' -                        }, -                        'metric_type': { -                            'type': 'int' -                        }, -                        'route_map': { -                            'type': 'str' +                "passive_interface": {"type": "list"}, +                "passive_interface_exclude": {"type": "list"}, +                "redistribute": { +                    "elements": "dict", +                    "options": { +                        "metric": {"type": "int"}, +                        "metric_type": {"type": "int"}, +                        "route_map": {"type": "str"}, +                        "route_type": { +                            "choices": [ +                                "bgp", +                                "connected", +                                "kernel", +                                "rip", +                                "static", +                            ], +                            "type": "str",                          }, -                        'route_type': { -                            'choices': -                            ['bgp', 'connected', 'kernel', 'rip', 'static'], -                            'type': -                            'str' -                        }                      }, -                    'type': 'list' -                }, -                'route_map': { -                    'type': 'list' +                    "type": "list",                  }, -                'timers': { -                    'options': { -                        'refresh': { -                            'options': { -                                'timers': { -                                    'type': 'int' -                                } -                            }, -                            'type': 'dict' +                "route_map": {"type": "list"}, +                "timers": { +                    "options": { +                        "refresh": { +                            "options": {"timers": {"type": "int"}}, +                            "type": "dict",                          }, -                        'throttle': { -                            'options': { -                                'spf': { -                                    'options': { -                                        'delay': { -                                            'type': 'int' -                                        }, -                                        'initial_holdtime': { -                                            'type': 'int' -                                        }, -                                        'max_holdtime': { -                                            'type': 'int' -                                        } +                        "throttle": { +                            "options": { +                                "spf": { +                                    "options": { +                                        "delay": {"type": "int"}, +                                        "initial_holdtime": {"type": "int"}, +                                        "max_holdtime": {"type": "int"},                                      }, -                                    'type': 'dict' +                                    "type": "dict",                                  }                              }, -                            'type': 'dict' -                        } +                            "type": "dict", +                        },                      }, -                    'type': 'dict' -                } +                    "type": "dict", +                },              }, -            'type': 'dict' +            "type": "dict",          },          "running_config": {"type": "str"}, -        'state': { -            'choices': [ -                'merged', 'replaced', 'deleted', 'parsed', 'gathered', -                'rendered' +        "state": { +            "choices": [ +                "merged", +                "replaced", +                "deleted", +                "parsed", +                "gathered", +                "rendered",              ], -            'default': -            'merged', -            'type': -            'str' -        } +            "default": "merged", +            "type": "str", +        },      }  # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py index 13645cd..fd25c17 100644 --- a/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py @@ -22,11 +22,16 @@ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.u      to_list,      remove_empties,  ) -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( +    Facts, +)  from ansible.module_utils.six import iteritems  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import ( -    list_diff_want_only, _in_target, _is_w_same, _bool_to_str +    list_diff_want_only, +    _in_target, +    _is_w_same, +    _bool_to_str,  ) @@ -36,9 +41,9 @@ class Ospfv2(ConfigBase):      The vyos_ospfv2 class      """ -    gather_subset = ['!all', '!min'] +    gather_subset = ["!all", "!min"] -    gather_network_resources = ['ospfv2'] +    gather_network_resources = ["ospfv2"]      def __init__(self, module):          super(Ospfv2, self).__init__(module) @@ -50,12 +55,10 @@ class Ospfv2(ConfigBase):          :returns: The current configuration as a dictionary          """ -        (facts, _warnings) = \ -            Facts(self._module).get_facts(self.gather_subset, -                self.gather_network_resources, data=data) -        ospfv2_facts = facts['ansible_network_resources'].get('ospfv2') -        if not ospfv2_facts: -            return [] +        (facts, _warnings) = Facts(self._module).get_facts( +            self.gather_subset, self.gather_network_resources, data=data +        ) +        ospfv2_facts = facts["ansible_network_resources"].get("ospfv2", {})          return ospfv2_facts      def execute_module(self): @@ -65,47 +68,48 @@ class Ospfv2(ConfigBase):          :returns: The result from module execution          """ -        result = {'changed': False} +        result = {"changed": False}          warnings = list()          commands = list()          if self.state in self.ACTION_STATES:              existing_ospfv2_facts = self.get_ospfv2_facts()          else: -            existing_ospfv2_facts = [] +            existing_ospfv2_facts = {} -        if self.state in self.ACTION_STATES or self.state == 'rendered': +        if self.state in self.ACTION_STATES or self.state == "rendered":              commands.extend(self.set_config(existing_ospfv2_facts))          if commands and self.state in self.ACTION_STATES:              if not self._module.check_mode:                  self._connection.edit_config(commands) -            result['changed'] = True +            result["changed"] = True          if self.state in self.ACTION_STATES: -            result['commands'] = commands +            result["commands"] = commands -        if self.state in self.ACTION_STATES or self.state == 'gathered': +        if self.state in self.ACTION_STATES or self.state == "gathered":              changed_ospfv2_facts = self.get_ospfv2_facts() -        elif self.state == 'rendered': -            result['rendered'] = commands -        elif self.state == 'parsed': -            running_config = self._module.params['running_config'] +        elif self.state == "rendered": +            result["rendered"] = commands +        elif self.state == "parsed": +            running_config = self._module.params["running_config"]              if not running_config: -                self._module.fail_json(msg='value of running_config parameter must not be empty for state parsed') -            result['parsed'] = \ -                self.get_ospfv2_facts(data=running_config) +                self._module.fail_json( +                    msg="value of running_config parameter must not be empty for state parsed" +                ) +            result["parsed"] = self.get_ospfv2_facts(data=running_config)          else: -            changed_ospfv2_facts = [] +            changed_ospfv2_facts = {}          if self.state in self.ACTION_STATES: -            result['before'] = existing_ospfv2_facts -            if result['changed']: -                result['after'] = changed_ospfv2_facts -        elif self.state == 'gathered': -            result['gathered'] = changed_ospfv2_facts +            result["before"] = existing_ospfv2_facts +            if result["changed"]: +                result["after"] = changed_ospfv2_facts +        elif self.state == "gathered": +            result["gathered"] = changed_ospfv2_facts -        result['warnings'] = warnings +        result["warnings"] = warnings          return result      def set_config(self, existing_ospfv2_facts): @@ -117,7 +121,7 @@ class Ospfv2(ConfigBase):                    to the desired configuration          """ -        want = self._module.params['config'] +        want = self._module.params["config"]          have = existing_ospfv2_facts          resp = self.set_state(want, have)          return to_list(resp) @@ -133,15 +137,21 @@ class Ospfv2(ConfigBase):          """          commands = [] -        if self.state in ('merged', 'replaced', 'overridden', 'rendered' -                          ) and not w: -            self._module.fail_json(msg='value of config parameter must not be empty for state {0}'.format(self.state)) - -        if self.state == 'deleted': -            commands.extend(self._state_deleted(w, h)) -        elif self.state in ('merged', 'rendered'): +        if ( +            self.state in ("merged", "replaced", "overridden", "rendered") +            and not w +        ): +            self._module.fail_json( +                msg="value of config parameter must not be empty for state {0}".format( +                    self.state +                ) +            ) + +        if self.state == "deleted": +            commands.extend(self._state_deleted(h)) +        elif self.state in ("merged", "rendered"):              commands.extend(self._state_merged(w, h)) -        elif self.state == 'replaced': +        elif self.state == "replaced":              commands.extend(self._state_replaced(w, h))          return commands @@ -170,8 +180,7 @@ class Ospfv2(ConfigBase):          commands = []          if have: -            commands.extend(self._render_ospf_param(have, want, -                            opr=False)) +            commands.extend(self._render_ospf_param(have, want, opr=False))          commands.extend(self._render_ospf_param(want, have))          return commands @@ -187,7 +196,7 @@ class Ospfv2(ConfigBase):          commands.extend(self._render_ospf_param(want, have))          return commands -    def _state_deleted(self, want, have): +    def _state_deleted(self, have):          """ The command generator when state is deleted          :rtype: A list @@ -196,26 +205,8 @@ class Ospfv2(ConfigBase):          """          commands = [] -        if want and have: -            for (key, val) in iteritems(want): -                if key in have: -                    if key == 'areas': -                        h_areas = have.get(key) or [] -                        key = 'area' -                        for area in h_areas: -                            h_vlist = area.get('virtual_link') or [] -                            if h_vlist: -                                for vlink in h_vlist: -                                    cmd = self._compute_command( -                                        key=key + ' ' + area['area_id'], attr='virtual_link', -                                        val=vlink['address'], opr=False) -                                    commands.append(cmd) -                            commands.append(self._compute_command(key=key, -                                    attr=area['area_id'], opr=False)) -                    commands.append(self._compute_command(attr=key, -                                    opr=False)) -        elif have: -            commands.append('delete protocols ospf') +        if have: +            commands.append("delete protocols ospf")          return commands      def _render_ospf_param(self, want, have, opr=True): @@ -231,16 +222,25 @@ class Ospfv2(ConfigBase):          commands = []          w = deepcopy(remove_empties(want)) -        leaf = ('default_metric', 'log_adjacency_changes') +        leaf = ("default_metric", "log_adjacency_changes")          if w:              for (key, val) in iteritems(w):                  if opr and key in leaf and not _is_w_same(w, have, key): -                    commands.append(self._form_attr_cmd(attr=key, -                                    val=_bool_to_str(val), opr=opr)) +                    commands.append( +                        self._form_attr_cmd( +                            attr=key, val=_bool_to_str(val), opr=opr +                        ) +                    )                  elif not opr and key in leaf and not _in_target(have, key): -                    commands.append(self._form_attr_cmd(attr=key, val=_bool_to_str(val), opr=opr)) +                    commands.append( +                        self._form_attr_cmd( +                            attr=key, val=_bool_to_str(val), opr=opr +                        ) +                    )                  else: -                    commands.extend(self._render_child_param(w, have, key, opr)) +                    commands.extend( +                        self._render_child_param(w, have, key, opr) +                    )          return commands      def _render_child_param(self, w, h, key, opr=True): @@ -255,22 +255,23 @@ class Ospfv2(ConfigBase):          """          commands = [] -        if key in ('neighbor', 'redistribute'): -            commands.extend(self._render_list_dict_param(key, w, h, -                            opr=opr)) -        elif key in ('default_information', 'max_metric'): -            commands.extend(self._render_nested_dict_param(key, w, h, -                            opr=opr)) -        elif key in ('mpls_te', 'auto_cost', 'parameters', 'auto_cost'): +        if key in ("neighbor", "redistribute"): +            commands.extend(self._render_list_dict_param(key, w, h, opr=opr)) +        elif key in ("default_information", "max_metric"): +            commands.extend(self._render_nested_dict_param(key, w, h, opr=opr)) +        elif key in ("mpls_te", "auto_cost", "parameters", "auto_cost"):              commands.extend(self._render_dict_param(key, w, h, opr=opr)) -        elif key in ('route_map', 'passive_interface', -                     'passive_interface_exclude'): +        elif key in ( +            "route_map", +            "passive_interface", +            "passive_interface_exclude", +        ):              commands.extend(self._render_list_param(key, w, h, opr=opr)) -        elif key == 'areas': +        elif key == "areas":              commands.extend(self._render_areas(key, w, h, opr=opr)) -        elif key == 'timers': +        elif key == "timers":              commands.extend(self._render_timers(key, w, h, opr=opr)) -        elif key == 'distance': +        elif key == "distance":              commands.extend(self._render_distance(key, w, h, opr=opr))          return commands @@ -291,24 +292,50 @@ class Ospfv2(ConfigBase):          if not opr and not h:              commands.append(self._form_attr_cmd(attr=attr, opr=opr))          elif want[attr]: -            leaf_dict = {'auto_cost': 'reference_bandwidth', -                         'mpls_te': ('enabled', 'router_address'), -                         'parameters': ('router_id', 'abr_type', -                         'opaque_lsa', 'rfc1583_compatibility')} +            leaf_dict = { +                "auto_cost": "reference_bandwidth", +                "mpls_te": ("enabled", "router_address"), +                "parameters": ( +                    "router_id", +                    "abr_type", +                    "opaque_lsa", +                    "rfc1583_compatibility", +                ), +            }              leaf = leaf_dict[attr]              for (item, value) in iteritems(want[attr]): -                if opr and item in leaf and not _is_w_same(want[attr], h, item): -                    if item == 'enabled': -                        item = 'enable' -                    if item in ('opaque_lsa', 'enable', 'rfc1583_compatibility'): -                        commands.append(self._form_attr_cmd(key=attr, attr=item, opr=opr)) +                if ( +                    opr +                    and item in leaf +                    and not _is_w_same(want[attr], h, item) +                ): +                    if item == "enabled": +                        item = "enable" +                    if item in ( +                        "opaque_lsa", +                        "enable", +                        "rfc1583_compatibility", +                    ): +                        commands.append( +                            self._form_attr_cmd(key=attr, attr=item, opr=opr) +                        )                      else: -                        commands.append(self._form_attr_cmd(key=attr, attr=item, val=value, opr=opr)) +                        commands.append( +                            self._form_attr_cmd( +                                key=attr, attr=item, val=value, opr=opr +                            ) +                        )                  elif not opr and item in leaf and not _in_target(h, item): -                    if item == 'enabled': -                        commands.append(self._form_attr_cmd(key=attr, attr='enable', opr=opr)) +                    if item == "enabled": +                        commands.append( +                            self._form_attr_cmd( +                                key=attr, attr="enable", opr=opr +                            ) +                        )                      else: -                        commands.append(self._form_attr_cmd(key=attr, attr=item, opr=opr)) +                        commands.append( +                            self._form_attr_cmd(key=attr, attr=item, opr=opr) +                        )          return commands      def _render_list_param(self, attr, want, have, cmd=None, opr=True): @@ -334,24 +361,31 @@ class Ospfv2(ConfigBase):              if opr:                  members = list_diff_want_only(w, h)                  for member in members: -                    command = cmd + attr.replace('_', '-') + ' ' -                    if attr == 'network': -                        command += member['address'] +                    command = cmd + attr.replace("_", "-") + " " +                    if attr == "network": +                        command += member["address"]                      else:                          command += member                      commands.append(command)              elif not opr:                  if h:                      for member in w: -                        if attr == 'network': -                            if not self.search_obj_in_have(h, member, 'address'): -                                commands.append(cmd + attr.replace('_','-') + -                                                ' ' + member['address']) +                        if attr == "network": +                            if not self.search_obj_in_have( +                                h, member, "address" +                            ): +                                commands.append( +                                    cmd +                                    + attr.replace("_", "-") +                                    + " " +                                    + member["address"] +                                )                          elif member not in h: -                            commands.append(cmd + attr.replace('_', '-') + -                                            ' ' + member) +                            commands.append( +                                cmd + attr.replace("_", "-") + " " + member +                            )                  else: -                    commands.append(cmd + ' ' + attr.replace('_', '-')) +                    commands.append(cmd + " " + attr.replace("_", "-"))          return commands      def _render_vlink(self, attr, want, have, cmd=None, opr=True): @@ -368,53 +402,81 @@ class Ospfv2(ConfigBase):          commands = []          h = [] -        name = {'virtual_link': 'address'} -        leaf_dict = {'virtual_link': ('address', 'dead_interval', -                     'transmit_delay', 'hello_interval', -                     'retransmit_interval')} +        name = {"virtual_link": "address"} +        leaf_dict = { +            "virtual_link": ( +                "address", +                "dead_interval", +                "transmit_delay", +                "hello_interval", +                "retransmit_interval", +            ) +        }          leaf = leaf_dict[attr]          w = want.get(attr) or []          if have:              h = have.get(attr) or []          if not opr and not h: -            commands.append(cmd + attr.replace('_', '-')) +            commands.append(cmd + attr.replace("_", "-"))          elif w:              for w_item in w:                  for (key, val) in iteritems(w_item):                      if not cmd:                          cmd = self._compute_command(opr=opr)                      h_item = self.search_obj_in_have(h, w_item, name[attr]) -                    if opr and key in leaf and not _is_w_same(w_item, h_item, key): -                        if key in 'address': -                            commands.append(cmd -                                            + attr.replace('_', '-') -                                            + ' ' + str(val)) +                    if ( +                        opr +                        and key in leaf +                        and not _is_w_same(w_item, h_item, key) +                    ): +                        if key in "address": +                            commands.append( +                                cmd + attr.replace("_", "-") + " " + str(val) +                            )                          else: -                            commands.append(cmd + attr.replace('_', '-') -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key.replace('_', '-') -                                            + ' ' + str(val)) -                    elif not opr and key in leaf and not _in_target(h_item, key): -                        if key in 'address': -                            commands.append(cmd + attr.replace('_', '-') -                                            + ' ' + str(val)) +                            commands.append( +                                cmd +                                + attr.replace("_", "-") +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + str(val) +                            ) +                    elif ( +                        not opr and key in leaf and not _in_target(h_item, key) +                    ): +                        if key in "address": +                            commands.append( +                                cmd + attr.replace("_", "-") + " " + str(val) +                            )                          else: -                            commands.append(cmd + attr.replace('_', '-') -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key) -                    elif key == 'authentication': -                        commands.extend(self._render_vlink_auth( -                            attr, -                            key, -                            w_item, -                            h_item, -                            w_item['address'], -                            cmd, -                            opr, -                            )) +                            commands.append( +                                cmd +                                + attr.replace("_", "-") +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key +                            ) +                    elif key == "authentication": +                        commands.extend( +                            self._render_vlink_auth( +                                attr, +                                key, +                                w_item, +                                h_item, +                                w_item["address"], +                                cmd, +                                opr, +                            ) +                        )          return commands -    def _render_vlink_auth(self, attr, key, want, have, address, cmd=None, opr=True): +    def _render_vlink_auth( +        self, attr, key, want, have, address, cmd=None, opr=True +    ):          """          This function forms the set/delete commands based on the 'opr' type          for attributes with in desired list of dictionary. @@ -432,9 +494,8 @@ class Ospfv2(ConfigBase):          w = want.get(key) or {}          if have:              h = have.get(key) or {} -        cmd += attr.replace('_', '-') + ' ' + address + ' ' + key + ' ' -        commands.extend(self._render_list_dict_param('md5', w, h, cmd, -                        opr)) +        cmd += attr.replace("_", "-") + " " + address + " " + key + " " +        commands.extend(self._render_list_dict_param("md5", w, h, cmd, opr))          return commands      def _render_list_dict_param(self, attr, want, have, cmd=None, opr=True): @@ -452,20 +513,30 @@ class Ospfv2(ConfigBase):          commands = []          h = []          name = { -            'redistribute': 'route_type', -            'neighbor': 'neighbor_id', -            'range': 'address', -            'md5': 'key_id', -            'vlink': 'address', -            } +            "redistribute": "route_type", +            "neighbor": "neighbor_id", +            "range": "address", +            "md5": "key_id", +            "vlink": "address", +        }          leaf_dict = { -            'md5': 'md5_key', -            'redistribute': ('metric', 'route_map', 'route_type', 'metric_type'), -            'neighbor': ('priority', 'poll_interval', 'neighbor_id'), -            'range': ('cost', 'address', 'substitute', 'not_advertise'), -            'vlink': ('address', 'dead_interval', 'transmit_delay', -                      'hello_interval', 'retransmit_interval'), -            } +            "md5": "md5_key", +            "redistribute": ( +                "metric", +                "route_map", +                "route_type", +                "metric_type", +            ), +            "neighbor": ("priority", "poll_interval", "neighbor_id"), +            "range": ("cost", "address", "substitute", "not_advertise"), +            "vlink": ( +                "address", +                "dead_interval", +                "transmit_delay", +                "hello_interval", +                "retransmit_interval", +            ), +        }          leaf = leaf_dict[attr]          w = want.get(attr) or []          if have: @@ -478,39 +549,81 @@ class Ospfv2(ConfigBase):                      if not cmd:                          cmd = self._compute_command(opr=opr)                      h_item = self.search_obj_in_have(h, w_item, name[attr]) -                    if opr and key in leaf and not _is_w_same(w_item, h_item, key): -                        if key in ('route_type', 'neighbor_id', -                                   'address', 'key_id'): -                            commands.append(cmd + attr + ' ' + str(val)) -                        elif key == 'cost': -                            commands.append(cmd + attr -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key -                                            + ' ' + str(val)) -                        elif key == 'not_advertise': -                            commands.append(cmd + attr -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key.replace('_', '-')) -                        elif key == 'md5_key': -                            commands.append(cmd + attr -                                            + ' ' + 'key-id' -                                            + ' ' + str(w_item[name[attr]]) -                                            + ' ' + key.replace('_', '-') -                                            + ' ' + w_item[key]) +                    if ( +                        opr +                        and key in leaf +                        and not _is_w_same(w_item, h_item, key) +                    ): +                        if key in ( +                            "route_type", +                            "neighbor_id", +                            "address", +                            "key_id", +                        ): +                            commands.append(cmd + attr + " " + str(val)) +                        elif key == "cost": +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key +                                + " " +                                + str(val) +                            ) +                        elif key == "not_advertise": +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key.replace("_", "-") +                            ) +                        elif key == "md5_key": +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + "key-id" +                                + " " +                                + str(w_item[name[attr]]) +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + w_item[key] +                            )                          else: -                            commands.append(cmd + attr -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key.replace('_', '-') -                                            + ' ' + str(val)) -                    elif not opr and key in leaf \ -                        and not _in_target(h_item, key): -                        if key in ('route_type', 'neighbor_id', -                                   'address', 'key_id'): -                            commands.append(cmd + attr + ' ' + str(val)) +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + str(val) +                            ) +                    elif ( +                        not opr and key in leaf and not _in_target(h_item, key) +                    ): +                        if key in ( +                            "route_type", +                            "neighbor_id", +                            "address", +                            "key_id", +                        ): +                            commands.append(cmd + attr + " " + str(val))                          else: -                            commands.append(cmd + attr -                                            + ' ' + w_item[name[attr]] -                                            + ' ' + key) +                            commands.append( +                                cmd +                                + attr +                                + " " +                                + w_item[name[attr]] +                                + " " +                                + key +                            )          return commands      def _render_nested_dict_param(self, attr, want, have, opr=True): @@ -526,10 +639,19 @@ class Ospfv2(ConfigBase):          """          commands = [] -        attr_dict = {'default_information': 'originate', -                     'max_metric': 'router_lsa'} -        leaf_dict = {'default_information': ('always', 'metric', 'metric_type', 'route_map'), -                     'max_metric': ('administrative', 'on_startup', 'on_shutdown')} +        attr_dict = { +            "default_information": "originate", +            "max_metric": "router_lsa", +        } +        leaf_dict = { +            "default_information": ( +                "always", +                "metric", +                "metric_type", +                "route_map", +            ), +            "max_metric": ("administrative", "on_startup", "on_shutdown"), +        }          h = {}          w = want.get(attr) or {}          if have: @@ -546,20 +668,38 @@ class Ospfv2(ConfigBase):                  if h and key in h.keys():                      h_attrib = h.get(key) or {}                  for (item, val) in iteritems(w[key]): -                    if opr and item in leaf and not _is_w_same(w[key], h_attrib, item): -                        if item in ('administrative', 'always') and val: -                            commands.append(cmd + attr.replace('_', '-') -                                            + ' ' + key.replace('_', '-') -                                            + ' ' + item.replace('_', '-')) -                        elif item not in ('administrative', 'always'): -                            commands.append(cmd + attr.replace('_', '-') -                                            + ' ' + key.replace('_', '-') -                                            + ' ' + item.replace('_', '-') -                                            + ' ' + str(val)) -                    elif not opr and item in leaf \ -                        and not _in_target(h_attrib, item): - -                        commands.append(cmd + attr + ' ' + item) +                    if ( +                        opr +                        and item in leaf +                        and not _is_w_same(w[key], h_attrib, item) +                    ): +                        if item in ("administrative", "always") and val: +                            commands.append( +                                cmd +                                + attr.replace("_", "-") +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + item.replace("_", "-") +                            ) +                        elif item not in ("administrative", "always"): +                            commands.append( +                                cmd +                                + attr.replace("_", "-") +                                + " " +                                + key.replace("_", "-") +                                + " " +                                + item.replace("_", "-") +                                + " " +                                + str(val) +                            ) +                    elif ( +                        not opr +                        and item in leaf +                        and not _in_target(h_attrib, item) +                    ): + +                        commands.append(cmd + attr + " " + item)          return commands      def _render_areas(self, attr, want, have, opr=True): @@ -576,43 +716,84 @@ class Ospfv2(ConfigBase):          commands = []          h_lst = {}          w_lst = want.get(attr) or [] -        l_set = ('area_id', 'shortcut', 'authentication') +        l_set = ("area_id", "shortcut", "authentication")          if have:              h_lst = have.get(attr) or []          if not opr and not h_lst: -            commands.append(self._form_attr_cmd(attr='area', opr=opr)) +            commands.append(self._form_attr_cmd(attr="area", opr=opr))          elif w_lst:              for w_area in w_lst: -                cmd = self._compute_command( -                    key='area', attr=_bool_to_str(w_area['area_id']), opr=opr -                ) + ' ' -                h_area = self.search_obj_in_have(h_lst, w_area, 'area_id') +                cmd = ( +                    self._compute_command( +                        key="area", +                        attr=_bool_to_str(w_area["area_id"]), +                        opr=opr, +                    ) +                    + " " +                ) +                h_area = self.search_obj_in_have(h_lst, w_area, "area_id")                  if not opr and not h_area: -                    commands.append(self._form_attr_cmd(key='area', -                                    attr=w_area['area_id'], opr=opr)) +                    commands.append( +                        self._form_attr_cmd( +                            key="area", attr=w_area["area_id"], opr=opr +                        ) +                    )                  else:                      for (key, val) in iteritems(w_area): -                        if opr and key in l_set and not _is_w_same(w_area, h_area, key): -                            if key == 'area_id': -                                commands.append(self._form_attr_cmd(attr='area', -                                                                    val=_bool_to_str(val), opr=opr)) +                        if ( +                            opr +                            and key in l_set +                            and not _is_w_same(w_area, h_area, key) +                        ): +                            if key == "area_id": +                                commands.append( +                                    self._form_attr_cmd( +                                        attr="area", +                                        val=_bool_to_str(val), +                                        opr=opr, +                                    ) +                                )                              else: -                                commands.append(cmd + key + ' ' + -                                                _bool_to_str(val).replace('_', '-')) +                                commands.append( +                                    cmd +                                    + key +                                    + " " +                                    + _bool_to_str(val).replace("_", "-") +                                )                          elif not opr and key in l_set: -                            if key == 'area_id' and not _in_target(h_area, key): +                            if key == "area_id" and not _in_target( +                                h_area, key +                            ):                                  commands.append(cmd)                                  continue -                            elif key != 'area_id' and not _in_target(h_area, key): -                                commands.append(cmd + val + ' ' + key) -                        elif key == 'area_type': -                            commands.extend(self._render_area_type(w_area, h_area, key, cmd, opr)) -                        elif key == 'network': -                            commands.extend(self._render_list_param(key, w_area, h_area, cmd, opr)) -                        elif key == 'range': -                            commands.extend(self._render_list_dict_param(key, w_area, h_area, cmd, opr)) -                        elif key == 'virtual_link': -                            commands.extend(self._render_vlink(key, w_area, h_area, cmd, opr)) +                            elif key != "area_id" and not _in_target( +                                h_area, key +                            ): +                                commands.append(cmd + val + " " + key) +                        elif key == "area_type": +                            commands.extend( +                                self._render_area_type( +                                    w_area, h_area, key, cmd, opr +                                ) +                            ) +                        elif key == "network": +                            commands.extend( +                                self._render_list_param( +                                    key, w_area, h_area, cmd, opr +                                ) +                            ) +                        elif key == "range": +                            commands.extend( +                                self._render_list_dict_param( +                                    key, w_area, h_area, cmd, opr +                                ) +                            ) +                        elif key == "virtual_link": +                            commands.extend( +                                self._render_vlink( +                                    key, w_area, h_area, cmd, opr +                                ) +                            )          return commands      def _render_area_type(self, want, have, attr, cmd, opr=True): @@ -633,24 +814,36 @@ class Ospfv2(ConfigBase):          if have:              h_type = have.get(attr) or {}          if not opr and not h_type: -            commands.append(cmd + attr.replace('_', '-')) +            commands.append(cmd + attr.replace("_", "-"))          elif w_type: -            key = 'normal' -            if opr and key in w_type.keys() and not _is_w_same(w_type, h_type, key): +            key = "normal" +            if ( +                opr +                and key in w_type.keys() +                and not _is_w_same(w_type, h_type, key) +            ):                  if not w_type[key] and h_type and h_type[key]: -                    commands.append(cmd.replace('set', 'delete') -                                    + attr.replace('_', '-') -                                    + ' ' + key) +                    commands.append( +                        cmd.replace("set", "delete") +                        + attr.replace("_", "-") +                        + " " +                        + key +                    )                  elif w_type[key]: -                    commands.append(cmd + attr.replace('_', '-') -                                    + ' ' + key) -            elif not opr and key in w_type.keys() and not (h_type -                    and key in h_type.keys()): -                commands.append(cmd + want['area'] -                                + ' ' + attr.replace('_', '-')) - -            a_type = {'nssa': ('set', 'default_cost', 'no_summary', 'translate'), -                      'stub': ('set', 'default_cost', 'no_summary')} +                    commands.append(cmd + attr.replace("_", "-") + " " + key) +            elif ( +                not opr +                and key in w_type.keys() +                and not (h_type and key in h_type.keys()) +            ): +                commands.append( +                    cmd + want["area"] + " " + attr.replace("_", "-") +                ) + +            a_type = { +                "nssa": ("set", "default_cost", "no_summary", "translate"), +                "stub": ("set", "default_cost", "no_summary"), +            }              for key in a_type:                  w_area = want[attr].get(key) or {}                  h_area = {} @@ -658,29 +851,53 @@ class Ospfv2(ConfigBase):                      if h_type and key in h_type.keys():                          h_area = h_type.get(key) or {}                      for (item, val) in iteritems(w_type[key]): -                        if opr and item in a_type[key] \ -                                and not _is_w_same(w_type[key], h_area, item): -                            if item == 'set' and val: -                                commands.append(cmd + attr.replace('_', '-') -                                                + ' ' + key) +                        if ( +                            opr +                            and item in a_type[key] +                            and not _is_w_same(w_type[key], h_area, item) +                        ): +                            if item == "set" and val: +                                commands.append( +                                    cmd + attr.replace("_", "-") + " " + key +                                )                              elif not val and h_area and h_area[item]: -                                commands.append(cmd.replace('set', 'delete') -                                                + attr.replace('_', '-') -                                                + ' ' + key) -                            elif item != 'set': -                                commands.append(cmd + attr.replace('_', '-') -                                                + ' ' + key -                                                + ' ' + item.replace('_', '-') -                                                + ' ' + str(val)) -                        elif not opr and item in a_type[key] \ -                                and not (h_type and key in h_type): -                            if item == 'set': -                                commands.append(cmd + attr.replace('_', '-') -                                                + ' ' + key) +                                commands.append( +                                    cmd.replace("set", "delete") +                                    + attr.replace("_", "-") +                                    + " " +                                    + key +                                ) +                            elif item != "set": +                                commands.append( +                                    cmd +                                    + attr.replace("_", "-") +                                    + " " +                                    + key +                                    + " " +                                    + item.replace("_", "-") +                                    + " " +                                    + str(val) +                                ) +                        elif ( +                            not opr +                            and item in a_type[key] +                            and not (h_type and key in h_type) +                        ): +                            if item == "set": +                                commands.append( +                                    cmd + attr.replace("_", "-") + " " + key +                                )                              else: -                                commands.append(cmd + want['area'] -                                                + ' ' + attr.replace('_', '-') -                                                + ' ' + key + ' ' + item.replace('_', '-')) +                                commands.append( +                                    cmd +                                    + want["area"] +                                    + " " +                                    + attr.replace("_", "-") +                                    + " " +                                    + key +                                    + " " +                                    + item.replace("_", "-") +                                )          return commands      def _form_attr_cmd(self, key=None, attr=None, val=None, opr=True): @@ -693,9 +910,13 @@ class Ospfv2(ConfigBase):          :return: generated command.          """ -        return self._compute_command(key, attr=self._map_attrib(attr), val=val, opr=opr) +        return self._compute_command( +            key, attr=self._map_attrib(attr), val=val, opr=opr +        ) -    def _compute_command(self, key=None, attr=None, val=None, remove=False, opr=True): +    def _compute_command( +        self, key=None, attr=None, val=None, remove=False, opr=True +    ):          """          This function construct the add/delete command based on passed attributes.          :param key: parent key. @@ -706,13 +927,13 @@ class Ospfv2(ConfigBase):          """          if remove or not opr: -            cmd = 'delete protocols ospf ' +            cmd = "delete protocols ospf "          else: -            cmd = 'set protocols ospf ' +            cmd = "set protocols ospf "          if key: -            cmd += key.replace('_', '-') + ' ' +            cmd += key.replace("_", "-") + " "          if attr: -            cmd += attr.replace('_', '-') +            cmd += attr.replace("_", "-")          if val:              cmd += " '" + str(val) + "'"          return cmd @@ -725,5 +946,4 @@ class Ospfv2(ConfigBase):          :return: regex string          """ -        return ('disable' if attrib == 'disabled' -                 else attrib.replace('_', '-')) +        return "disable" if attrib == "disabled" else attrib.replace("_", "-") diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 17c7aa3..f1221f6 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -43,7 +43,7 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firew  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3 import (      Ospfv3Facts,  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv2.ospfv2 import ( -   Ospfv2Facts, +    Ospfv2Facts,  )  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (      Default, diff --git a/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py index 0467b72..d62fa9a 100644 --- a/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py @@ -15,9 +15,13 @@ __metaclass__ = type  from re import findall, search, M  from copy import deepcopy -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( +    utils, +) -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv2.ospfv2 import Ospfv2Args +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv2.ospfv2 import ( +    Ospfv2Args, +)  class Ospfv2Facts(object): @@ -26,11 +30,8 @@ class Ospfv2Facts(object):      """      def __init__( -        self, -        module, -        subspec='config', -        options='options', -        ): +        self, module, subspec="config", options="options", +    ):          self._module = module          self.argument_spec = Ospfv2Args.argument_spec @@ -69,9 +70,9 @@ class Ospfv2Facts(object):          if ospfv2:              objs = self.render_config(ospfv2)          facts = {} -        params = utils.validate_config(self.argument_spec,{'config': objs}) -        facts['ospfv2'] = utils.remove_empties(params['config']) -        ansible_facts['ansible_network_resources'].update(facts) +        params = utils.validate_config(self.argument_spec, {"config": objs}) +        facts["ospfv2"] = utils.remove_empties(params["config"]) +        ansible_facts["ansible_network_resources"].update(facts)          return ansible_facts      def render_config(self, conf): @@ -82,25 +83,35 @@ class Ospfv2Facts(object):          :returns: The generated config          """ -        conf = '\n'.join(filter(lambda x: x, conf)) -        a_lst = ['default_metric', 'log_adjacency_changes'] +        conf = "\n".join(filter(lambda x: x, conf)) +        a_lst = ["default_metric", "log_adjacency_changes"]          config = self.parse_attr(conf, a_lst)          if not config:              config = {} -        config['timers'] = self.parse_timers(conf) -        config['auto_cost'] = self.parse_auto_cost(conf) -        config['distance'] = self.parse_distance(conf) -        config['max_metric'] = self.parse_max_metric(conf) -        config['default_information'] = self.parse_def_info(conf) -        config['route_map'] = self.parse_leaf_list(conf, 'route-map') -        config['mpls_te'] = self.parse_attrib(conf, 'mpls_te', 'mpls-te') -        config['areas'] = self.parse_attrib_list(conf, 'area', 'area_id') -        config['parameters'] = self.parse_attrib(conf, 'parameters', 'parameters') -        config['neighbor'] = self.parse_attrib_list(conf, 'neighbor', 'neighbor_id') -        config['passive_interface'] = self.parse_leaf_list(conf, 'passive-interface') -        config['redistribute'] = self.parse_attrib_list(conf, 'redistribute', 'route_type') -        config['passive_interface_exclude'] = self.parse_leaf_list(conf, 'passive-interface-exclude') +        config["timers"] = self.parse_timers(conf) +        config["auto_cost"] = self.parse_auto_cost(conf) +        config["distance"] = self.parse_distance(conf) +        config["max_metric"] = self.parse_max_metric(conf) +        config["default_information"] = self.parse_def_info(conf) +        config["route_map"] = self.parse_leaf_list(conf, "route-map") +        config["mpls_te"] = self.parse_attrib(conf, "mpls_te", "mpls-te") +        config["areas"] = self.parse_attrib_list(conf, "area", "area_id") +        config["parameters"] = self.parse_attrib( +            conf, "parameters", "parameters" +        ) +        config["neighbor"] = self.parse_attrib_list( +            conf, "neighbor", "neighbor_id" +        ) +        config["passive_interface"] = self.parse_leaf_list( +            conf, "passive-interface" +        ) +        config["redistribute"] = self.parse_attrib_list( +            conf, "redistribute", "route_type" +        ) +        config["passive_interface_exclude"] = self.parse_leaf_list( +            conf, "passive-interface-exclude" +        )          return config      def parse_timers(self, conf): @@ -111,8 +122,8 @@ class Ospfv2Facts(object):          """          cfg_dict = {} -        cfg_dict['refresh'] = self.parse_refresh(conf, 'refresh') -        cfg_dict['throttle'] = self.parse_throttle(conf, 'spf') +        cfg_dict["refresh"] = self.parse_refresh(conf, "refresh") +        cfg_dict["throttle"] = self.parse_throttle(conf, "spf")          return cfg_dict      def parse_throttle(self, conf, attrib=None): @@ -135,7 +146,7 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ['timers'], match=attrib) +        cfg_dict = self.parse_attr(conf, ["timers"], match=attrib)          return cfg_dict      def parse_leaf_list(self, conf, attrib): @@ -148,10 +159,11 @@ class Ospfv2Facts(object):          """          lst = [] -        items = findall(r"^" + attrib + " (?:\'*)(\\S+)(?:\'*)", conf, M) +        items = findall(r"^" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M)          if items:              for i in set(items):                  lst.append(i.strip("'")) +                lst.sort()          return lst      def parse_distance(self, conf, attrib=None): @@ -162,8 +174,8 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ['global'], match=attrib) -        cfg_dict['ospf'] = self.parse_ospf(conf, 'ospf') +        cfg_dict = self.parse_attr(conf, ["global"], match=attrib) +        cfg_dict["ospf"] = self.parse_ospf(conf, "ospf")          return cfg_dict      def parse_ospf(self, conf, attrib=None): @@ -174,7 +186,7 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attrib(conf, 'ospf', match=attrib) +        cfg_dict = self.parse_attrib(conf, "ospf", match=attrib)          return cfg_dict      def parse_max_metric(self, conf): @@ -185,7 +197,9 @@ class Ospfv2Facts(object):          """          cfg_dict = {} -        cfg_dict['router_lsa'] = self.parse_attrib(conf, 'router_lsa', match='router-lsa') +        cfg_dict["router_lsa"] = self.parse_attrib( +            conf, "router_lsa", match="router-lsa" +        )          return cfg_dict      def parse_auto_cost(self, conf, attrib=None): @@ -196,8 +210,7 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ['reference_bandwidth'], -                                   match=attrib) +        cfg_dict = self.parse_attr(conf, ["reference_bandwidth"], match=attrib)          return cfg_dict      def parse_def_info(self, conf): @@ -208,7 +221,9 @@ class Ospfv2Facts(object):          """          cfg_dict = {} -        cfg_dict['originate'] = self.parse_attrib(conf, 'originate', 'originate') +        cfg_dict["originate"] = self.parse_attrib( +            conf, "originate", "originate" +        )          return cfg_dict      def parse_area(self, conf, area_id): @@ -219,13 +234,15 @@ class Ospfv2Facts(object):          :return: generated rule configuration dictionary.          """ -        rule = self.parse_attrib(conf, 'area_id', match=area_id) +        rule = self.parse_attrib(conf, "area_id", match=area_id)          r_sub = { -            'area_type': self.parse_area_type(conf, 'area-type'), -            'network': self.parse_network(conf), -            'range': self.parse_attrib_list(conf, 'range', 'address'), -            'virtual_link': self.parse_attrib_list(conf, 'virtual-link', 'address'), -            } +            "area_type": self.parse_area_type(conf, "area-type"), +            "network": self.parse_network(conf), +            "range": self.parse_attrib_list(conf, "range", "address"), +            "virtual_link": self.parse_attrib_list( +                conf, "virtual-link", "address" +            ), +        }          rule.update(r_sub)          return rule @@ -237,7 +254,7 @@ class Ospfv2Facts(object):          :return: generated rule configuration dictionary.          """ -        rule = self.parse_attrib(conf, 'key_id', match=key_id) +        rule = self.parse_attrib(conf, "key_id", match=key_id)          return rule      def parse_area_type(self, conf, attrib=None): @@ -248,9 +265,9 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ['normal'], match=attrib) -        cfg_dict['nssa'] = self.parse_attrib(conf, 'nssa', match='nssa') -        cfg_dict['stub'] = self.parse_attrib(conf, 'stub', match='stub') +        cfg_dict = self.parse_attr(conf, ["normal"], match=attrib) +        cfg_dict["nssa"] = self.parse_attrib(conf, "nssa", match="nssa") +        cfg_dict["stub"] = self.parse_attrib(conf, "stub", match="stub")          return cfg_dict      def parse_network(self, conf): @@ -265,9 +282,9 @@ class Ospfv2Facts(object):          if applications:              app_lst = []              for r in set(applications): -                obj = {'address': r.strip("'")} +                obj = {"address": r.strip("'")}                  app_lst.append(obj) -            a_lst = sorted(app_lst, key=lambda i: i['address']) +            a_lst = sorted(app_lst, key=lambda i: i["address"])          return a_lst      def parse_vlink(self, conf): @@ -277,9 +294,10 @@ class Ospfv2Facts(object):          :return: generated rule configuration dictionary          """ -        rule = self.parse_attrib(conf, 'vlink') -        r_sub = {'authentication': self.parse_authentication(conf, -                 'authentication')} +        rule = self.parse_attrib(conf, "vlink") +        r_sub = { +            "authentication": self.parse_authentication(conf, "authentication") +        }          rule.update(r_sub)          return rule @@ -291,9 +309,8 @@ class Ospfv2Facts(object):          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ['plaintext_password'], -                                   match=attrib) -        cfg_dict['md5'] = self.parse_attrib_list(conf, 'key-id', 'key_id') +        cfg_dict = self.parse_attr(conf, ["plaintext_password"], match=attrib) +        cfg_dict["md5"] = self.parse_attrib_list(conf, "key-id", "key_id")          return cfg_dict      def parse_attrib_list(self, conf, attrib, param): @@ -307,24 +324,30 @@ class Ospfv2Facts(object):          """          r_lst = [] -        if attrib == 'area': -            items = findall(r"^" + attrib.replace('_', '-') -                            + " (?:\'*)(\\S+)(?:\'*)", conf, M) -        elif attrib == 'key-id': -            items = findall(r"^.*" + attrib.replace('_', '-') -                            + " (?:\'*)(\\S+)(?:\'*)", conf, M) +        if attrib == "area": +            items = findall( +                r"^" + attrib.replace("_", "-") + " (?:'*)(\\S+)(?:'*)", +                conf, +                M, +            ) +        elif attrib == "key-id": +            items = findall( +                r"^.*" + attrib.replace("_", "-") + " (?:'*)(\\S+)(?:'*)", +                conf, +                M, +            )          else: -            items = findall(r"" + attrib + " (?:\'*)(\\S+)(?:\'*)", conf, M) +            items = findall(r"" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M)          if items:              a_lst = []              for item in set(items):                  i_regex = r" %s .+$" % item -                cfg = '\n'.join(findall(i_regex, conf, M)) -                if attrib == 'area': +                cfg = "\n".join(findall(i_regex, conf, M)) +                if attrib == "area":                      obj = self.parse_area(cfg, item) -                elif attrib == 'virtual-link': +                elif attrib == "virtual-link":                      obj = self.parse_vlink(cfg) -                elif attrib == 'key-id': +                elif attrib == "key-id":                      obj = self.parse_key(cfg, item)                  else:                      obj = self.parse_attrib(cfg, attrib) @@ -342,27 +365,32 @@ class Ospfv2Facts(object):          """          param_lst = { -            'key_id': ['md5_key'], -            'mpls_te': ['enabled', 'router_address'], -            'area_id': ['shortcut', 'authentication'], -            'neighbor': ['priority', 'poll_interval'], -            'stub': ['set', 'default_cost', 'no_summary'], -            'range': ['cost', 'substitute', 'not_advertise'], -            'ospf': ['external', 'inter_area', 'intra_area'], -            'spf': ['delay', 'max_holdtime', 'initial_holdtime'], -            'redistribute': ['metric', 'metric_type', 'route_map'], -            'nssa': ['set', 'translate', 'default_cost', 'no_summary'], -            'config_routes': ['default_metric', 'log_adjacency_changes' -                              ], -            'originate': ['always', 'metric', 'metric_type', 'route_map' -                          ], -            'router_lsa': ['administrative', 'on_shutdown', 'on_startup' -                           ], -            'parameters': ['abr_type', 'opaque_lsa', 'router_id', -                           'rfc1583_compatibility'], -            'vlink': ['dead_interval', 'hello_interval', -                      'transmit_delay', 'retransmit_interval'], -            } +            "key_id": ["md5_key"], +            "mpls_te": ["enabled", "router_address"], +            "area_id": ["shortcut", "authentication"], +            "neighbor": ["priority", "poll_interval"], +            "stub": ["set", "default_cost", "no_summary"], +            "range": ["cost", "substitute", "not_advertise"], +            "ospf": ["external", "inter_area", "intra_area"], +            "spf": ["delay", "max_holdtime", "initial_holdtime"], +            "redistribute": ["metric", "metric_type", "route_map"], +            "nssa": ["set", "translate", "default_cost", "no_summary"], +            "config_routes": ["default_metric", "log_adjacency_changes"], +            "originate": ["always", "metric", "metric_type", "route_map"], +            "router_lsa": ["administrative", "on_shutdown", "on_startup"], +            "parameters": [ +                "abr_type", +                "opaque_lsa", +                "router_id", +                "rfc1583_compatibility", +            ], +            "vlink": [ +                "dead_interval", +                "hello_interval", +                "transmit_delay", +                "retransmit_interval", +            ], +        }          cfg_dict = self.parse_attr(conf, param_lst[param], match)          return cfg_dict @@ -382,14 +410,13 @@ class Ospfv2Facts(object):              regex = self.map_regex(attrib)              if match: -                regex = match.replace('_', '-') + ' ' + regex +                regex = match.replace("_", "-") + " " + regex              if conf:                  if self.is_bool(attrib): -                    out = conf.find(attrib.replace('_', '-')) -                    dis = conf.find(attrib.replace('_', '-') -                                    + " 'disable'") +                    out = conf.find(attrib.replace("_", "-")) +                    dis = conf.find(attrib.replace("_", "-") + " 'disable'")                      if match: -                        if attrib == 'set' and conf.find(match) >= 1: +                        if attrib == "set" and conf.find(match) >= 1:                              config[attrib] = True                          en = conf.find(match + " 'enable'")                      if out >= 1: @@ -400,7 +427,7 @@ class Ospfv2Facts(object):                      elif match and en >= 1:                          config[attrib] = True                  else: -                    out = search(r"^.*" + regex + ' (.+)', conf, M) +                    out = search(r"^.*" + regex + " (.+)", conf, M)                      if out:                          val = out.group(1).strip("'")                          if self.is_num(attrib): @@ -416,9 +443,17 @@ class Ospfv2Facts(object):          :return: regex string          """ -        return ('disable' if attrib == 'disabled' else ('enable' -                 if attrib == 'enabled' else ('area' if attrib -                == 'area_id' else attrib.replace('_', '-')))) +        return ( +            "disable" +            if attrib == "disabled" +            else ( +                "enable" +                if attrib == "enabled" +                else ( +                    "area" if attrib == "area_id" else attrib.replace("_", "-") +                ) +            ) +        )      def is_bool(self, attrib):          """ @@ -428,15 +463,15 @@ class Ospfv2Facts(object):          """          bool_set = ( -            'set', -            'always', -            'normal', -            'enabled', -            'opaque_lsa', -            'not_advertise', -            'administrative', -            'rfc1583_compatibility', -            ) +            "set", +            "always", +            "normal", +            "enabled", +            "opaque_lsa", +            "not_advertise", +            "administrative", +            "rfc1583_compatibility", +        )          return True if attrib in bool_set else False      def is_num(self, attrib): @@ -447,18 +482,18 @@ class Ospfv2Facts(object):          """          num_set = ( -            'ospf', -            'delay', -            'metric', -            'inter_area', -            'intra_area', -            'on_startup', -            'metric_type', -            'on_shutdown', -            'max_holdtime', -            'poll_interval', -            'default_metric', -            'initial_holdtime', -            'key_id', -            ) +            "ospf", +            "delay", +            "metric", +            "inter_area", +            "intra_area", +            "on_startup", +            "metric_type", +            "on_shutdown", +            "max_holdtime", +            "poll_interval", +            "default_metric", +            "initial_holdtime", +            "key_id", +        )          return True if attrib in num_set else False diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py index c539beb..8fa2bfd 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -113,7 +113,7 @@ def get_lst_same_for_dicts(want, have, lst):  def list_diff_have_only(want_list, have_list): -    """ - +    """      This function generated the list containing values      that are only in have list.      :param want_list: @@ -238,7 +238,14 @@ def _bool_to_str(val):      :param val: bool value.      :return: enable/disable.      """ -    return "enable" if str(val) == "True" else "disable" if str(val) == "False" else val +    return ( +        "enable" +        if str(val) == "True" +        else "disable" +        if str(val) == "False" +        else val +    ) +  def _is_w_same(w, h, key): diff --git a/plugins/modules/vyos_ospfv2.py b/plugins/modules/vyos_ospfv2.py index 866ed76..9c40d9c 100644 --- a/plugins/modules/vyos_ospfv2.py +++ b/plugins/modules/vyos_ospfv2.py @@ -27,20 +27,18 @@ The module file for vyos_ospfv2  """  from __future__ import absolute_import, division, print_function +  __metaclass__ = type -ANSIBLE_METADATA = { -    'metadata_version': '1.1', -    'status': ['preview'], -    'supported_by': 'network' -} +ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Ansible"}  DOCUMENTATION = """  ---  module: vyos_ospfv2  version_added: 2.10 -short_description: This resource module configures and manages attributes of OSPFv2 routes on VyOS network devices. +short_description: OSPFV2 resource module  description: This resource module configures and manages attributes of OSPFv2 routes on VyOS network devices. +version_added: "1.0.0"  notes:    - Tested against VyOS 1.1.8 (helium).    - This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html). @@ -57,7 +55,7 @@ options:          elements: dict          suboptions:            area_id: -            description: Configured to discard packets. +            description: OSPFv2 area identity.              type: str            area_type:              description: Area type. @@ -67,27 +65,27 @@ options:                  description: Normal OSPFv2 area.                  type: bool                nssa: -                description: Nssa OSPFv2 area. +                description: NSSA OSPFv2 area.                  type: dict                  suboptions: -                  set:  -                    description: Enabling nssa. +                  set: +                    description: Enabling NSSA.                      type: bool                    default_cost: -                    description: Summary-default cost of nssa area. +                    description: Summary-default cost of NSSA area.                      type: int                    no_summary:                      description: Do not inject inter-area routes into stub.                      type: bool -                  translate:  -                    description: Nssa-abr. +                  translate: +                    description: NSSA-ABR.                      type: str                      choices: ['always', 'candidate', 'never'] -              stub:  +              stub:                  description: Stub OSPFv2 area.                  type: dict                  suboptions: -                  set:  +                  set:                      description: Enabling stub.                      type: bool                    default_cost: @@ -108,7 +106,7 @@ options:                address:                  required: True                  description: OSPFv2 IPv4 network address. -                type: str  +                type: str            range:              description: Summarize routes matching prefix (border routers only).              type: list @@ -162,7 +160,7 @@ options:                hello_interval:                  description: Interval between hello packets.                  type: int -              retransmit_interval:  +              retransmit_interval:                  description: Interval between retransmitting lost link state advertisements.                  type: int                transmit_delay: @@ -172,7 +170,7 @@ options:           description: Log changes in adjacency state.           type: str           choices: ['detail'] -      max_metric:  +      max_metric:          description: OSPFv2 maximum/infinite-distance metric.          type: dict          suboptions: @@ -185,10 +183,10 @@ options:                  type: bool                on_shutdown:                  description: Time to advertise self as stub-router. -                type: int    +                type: int                on_startup:                  description: Time to advertise self as stub-router -                type: int    +                type: int        auto_cost:          description: Calculate OSPFv2 interface cost according to bandwidth.          type: dict @@ -215,7 +213,7 @@ options:                  type: int                route_map:                  description: Route map references. -                type: str            +                type: str        default_metric:          description: Metric of redistributed routes          type: int @@ -226,11 +224,11 @@ options:            global:              description: Global OSPFv2 administrative distance.              type: int -          ospf:  +          ospf:              description: OSPFv2 administrative distance.              type: dict              suboptions: -              external:  +              external:                  description: Distance for external routes.                  type: int                inter_area: @@ -257,18 +255,18 @@ options:          suboptions:            neighbor_id:              description: Identity (number/IP address) of neighbor. -            type: str  +            type: str            poll_interval:              description: Seconds between dead neighbor polling interval.              type: int            priority:              description: Neighbor priority. -            type: int        +            type: int        parameters:          descriptions: OSPFv2 specific parameters.          type: dict -        suboptions:  -         abr_type:  +        suboptions: +         abr_type:             description: OSPFv2 ABR Type.             type: str             choices: ['cisco', 'ibm', 'shortcut', 'standard'] @@ -278,7 +276,7 @@ options:           rfc1583_compatibility:             description: Enable rfc1583 criteria for handling AS external routes.             type: bool -         router_id:  +         router_id:             description: Override the default router identifier.             type: str        passive_interface: @@ -287,11 +285,11 @@ options:        passive_interface_exclude:          description: Interface to exclude when using passive-interface default.          type: list -      redistribute:   +      redistribute:          description: Redistribute information from another routing protocol.          type: list          elements: dict -        suboptions:  +        suboptions:            route_type:              description: Route type to redistribute.              type: str @@ -304,10 +302,9 @@ options:              type: int            route_map:              description: Route map references. -            type: str  -       +            type: str        route_map: -        description: Filter routes installed in local route map.        +        description: Filter routes installed in local route map.          type: list        timers:          description: Adjust routing timers. @@ -339,13 +336,12 @@ options:                      type: int    running_config:      description: -    - The module, by default, will connect to the remote device and retrieve the current -      running-config to use as a base for comparing against the contents of source. -      There are times when it is not desirable to have the task get the current running-config -      for every task in a playbook.  The I(running_config) argument allows the implementer -      to pass in the configuration to use as the base config for comparison. This -      value of this option should be the output received from device by executing -      command C(show configuration commands | grep 'ospf') +      - This option is used only with state I(parsed). +      - The value of this option should be the output received from the VyOS device by executing +        the command B(show configuration commands | grep ospf). +      - The state I(parsed) reads the configuration from C(running_config) option and transforms +        it into Ansible structured data as per the resource module's argspec and the value is then +        returned in the I(parsed) key within the result.      type: str    state:      description: @@ -366,74 +362,74 @@ EXAMPLES = """  # Before state:  # -------------  # -# vyos@vyos# run show  configuration commands | grep ospf  -#  -# -- name: Merge the provided configuration with the exisiting running configuration -      vyos.vyos.vyos_ospfv2: -        config: -           log_adjacency_changes: 'detail' -           max_metric: -             router_lsa: -               administrative: true -               on_shutdown: 10 -               on_startup: 10 -           default_information: -             originate: -               always: true -               metric: 10 -               metric_type: 2 -               route_map: 'ingress' -           mpls_te: -             enabled: true -             router_address: '192.0.11.11' -           auto_cost: -             reference_bandwidth: 2 -           neighbor: -             - neighbor_id: '192.0.11.12' -               poll_interval: 10 -               priority: 2 -           redistribute: -             - route_type: 'bgp' -               metric: 10 -               metric_type: 2 -           passive_interface: -             - 'eth1' -             - 'eth2' -           parameters: -             router_id: '192.0.1.1' -             opaque_lsa: true -             rfc1583_compatibility: true -             abr_type: 'cisco' -           areas: -             - area_id: '2' -               area_type: -                 normal: true -               authentication: "plaintext-password" -               shortcut: 'enable' -             - area_id: '3' -               area_type: -                 nssa: -                  set: true -             - area_id: '4' -               area_type: -                 stub: -                  default_cost: 20 -               network: -                 - address: '192.0.2.0/24' -               range: -                 - address: '192.0.3.0/24' -                   cost: 10 -                 - address: '192.0.4.0/24' -                   cost: 12 -        state: merged +# vyos@vyos# run show  configuration commands | grep ospf +# +# +- name: Merge the provided configuration with the existing running configuration +  vyos.vyos.vyos_ospfv2: +    config: +      log_adjacency_changes: 'detail' +      max_metric: +        router_lsa: +          administrative: true +          on_shutdown: 10 +          on_startup: 10 +        default_information: +          originate: +            always: true +            metric: 10 +            metric_type: 2 +            route_map: 'ingress' +        mpls_te: +          enabled: true +          router_address: '192.0.11.11' +        auto_cost: +           reference_bandwidth: 2 +        neighbor: +          - neighbor_id: '192.0.11.12' +            poll_interval: 10 +            priority: 2 +        redistribute: +          - route_type: 'bgp' +            metric: 10 +            metric_type: 2 +        passive_interface: +          - 'eth1' +          - 'eth2' +        parameters: +          router_id: '192.0.1.1' +          opaque_lsa: true +          rfc1583_compatibility: true +          abr_type: 'cisco' +        areas: +          - area_id: '2' +            area_type: +              normal: true +              authentication: "plaintext-password" +              shortcut: 'enable' +          - area_id: '3' +            area_type: +              nssa: +                set: true +          - area_id: '4' +            area_type: +              stub: +                default_cost: 20 +            network: +              - address: '192.0.2.0/24' +            range: +              - address: '192.0.3.0/24' +                cost: 10 +              - address: '192.0.4.0/24' +            cost: 12 +    state: merged  #  #  # -------------------------  # Module Execution Result  # -------------------------  # -# before": [] +# before": {}  #  #    "commands": [  #       "set protocols ospf mpls-te enable", @@ -606,31 +602,31 @@ EXAMPLES = """  # Before state:  # -------------  # -# vyos@vyos# run show  configuration commands | grep ospf  -#  -# -- name: Merge the provided configuration to update exisiting running configuration -      vyos.vyos.vyos_ospfv2: -        config: -           areas: -             - area_id: '2' -               area_type: -                 normal: true -               authentication: "plaintext-password" -               shortcut: 'enable' -             - area_id: '3' -               area_type: -                 nssa: -                  set: false -             - area_id: '4' -               area_type: -                 stub: -                  default_cost: 20 -               network: -                 - address: '192.0.2.0/24' -                 - address: '192.0.22.0/24' -                 - address: '192.0.32.0/24' -        state: merged +# vyos@vyos# run show  configuration commands | grep ospf +# +# +- name: Merge the provided configuration to update existing running configuration +  vyos.vyos.vyos_ospfv2: +    config: +      areas: +        - area_id: '2' +          area_type: +            normal: true +          authentication: "plaintext-password" +          shortcut: 'enable' +        - area_id: '3' +          area_type: +            nssa: +              set: false +        - area_id: '4' +          area_type: +            stub: +              default_cost: 20 +          network: +            - address: '192.0.2.0/24' +            - address: '192.0.22.0/24' +            - address: '192.0.32.0/24' +    state: merged  #  #  # ------------------------- @@ -901,59 +897,59 @@ EXAMPLES = """  # set protocols ospf redistribute bgp metric-type '2'  #  - name: Replace ospfv2 routes attributes configuration. -      vyos.vyos.vyos_ospfv2: -        config: -           log_adjacency_changes: 'detail' -           max_metric: -             router_lsa: -               administrative: true -               on_shutdown: 10 -               on_startup: 10 -           default_information: -             originate: -               always: true -               metric: 10 -               metric_type: 2 -               route_map: 'ingress' -           mpls_te: -             enabled: true -             router_address: '192.0.22.22' -           auto_cost: -             reference_bandwidth: 2 -           neighbor: -             - neighbor_id: '192.0.11.12' -               poll_interval: 10 -               priority: 2 -           redistribute: -             - route_type: 'bgp' -               metric: 10 -               metric_type: 2 -           passive_interface: -             - 'eth1' -           parameters: -             router_id: '192.0.1.1' -             opaque_lsa: true -             rfc1583_compatibility: true -             abr_type: 'cisco' -           areas: -             - area_id: '2' -               area_type: -                 normal: true -               authentication: "plaintext-password" -               shortcut: 'enable' -             - area_id: '4' -               area_type: -                 stub: -                  default_cost: 20 -               network: -                 - address: '192.0.2.0/24' -                 - address: '192.0.12.0/24' -                 - address: '192.0.22.0/24' -                 - address: '192.0.32.0/24' -               range: -                 - address: '192.0.42.0/24' -                   cost: 10 -        state: replaced +  vyos.vyos.vyos_ospfv2: +    config: +      log_adjacency_changes: 'detail' +      max_metric: +        router_lsa: +          administrative: true +          on_shutdown: 10 +          on_startup: 10 +        default_information: +          originate: +            always: true +            metric: 10 +            metric_type: 2 +            route_map: 'ingress' +        mpls_te: +          enabled: true +          router_address: '192.0.22.22' +        auto_cost: +          reference_bandwidth: 2 +        neighbor: +          - neighbor_id: '192.0.11.12' +            poll_interval: 10 +            priority: 2 +        redistribute: +          - route_type: 'bgp' +            metric: 10 +            metric_type: 2 +        passive_interface: +          - 'eth1' +        parameters: +          router_id: '192.0.1.1' +          opaque_lsa: true +          rfc1583_compatibility: true +          abr_type: 'cisco' +        areas: +          - area_id: '2' +            area_type: +              normal: true +            authentication: "plaintext-password" +            shortcut: 'enable' +          - area_id: '4' +            area_type: +              stub: +                default_cost: 20 +            network: +              - address: '192.0.2.0/24' +              - address: '192.0.12.0/24' +              - address: '192.0.22.0/24' +              - address: '192.0.32.0/24' +            range: +              - address: '192.0.42.0/24' +                cost: 10 +    state: replaced  #  #  # ------------------------- @@ -1154,7 +1150,7 @@ EXAMPLES = """  #            }  #        ]  #    } -#  +#  # After state:  # -------------  # @@ -1194,63 +1190,63 @@ EXAMPLES = """  #  #  - name: Render the commands for provided  configuration -      vyos.vyos.vyos_ospfv2: -        config: -           log_adjacency_changes: 'detail' -           max_metric: -             router_lsa: -               administrative: true -               on_shutdown: 10 -               on_startup: 10 -           default_information: -             originate: -               always: true -               metric: 10 -               metric_type: 2 -               route_map: 'ingress' -           mpls_te: -             enabled: true -             router_address: '192.0.11.11' -           auto_cost: -             reference_bandwidth: 2 -           neighbor: -             - neighbor_id: '192.0.11.12' -               poll_interval: 10 -               priority: 2 -           redistribute: -             - route_type: 'bgp' -               metric: 10 -               metric_type: 2 -           passive_interface: -             - 'eth1' -             - 'eth2' -           parameters: -             router_id: '192.0.1.1' -             opaque_lsa: true -             rfc1583_compatibility: true -             abr_type: 'cisco' -           areas: -             - area_id: '2' -               area_type: -                 normal: true -               authentication: "plaintext-password" -               shortcut: 'enable' -             - area_id: '3' -               area_type: -                 nssa: -                  set: true -             - area_id: '4' -               area_type: -                 stub: -                  default_cost: 20 -               network: -                 - address: '192.0.2.0/24' -               range: -                 - address: '192.0.3.0/24' -                   cost: 10 -                 - address: '192.0.4.0/24' -                   cost: 12 -        state: rendered +  vyos.vyos.vyos_ospfv2: +    config: +      log_adjacency_changes: 'detail' +      max_metric: +        router_lsa: +          administrative: true +          on_shutdown: 10 +          on_startup: 10 +        default_information: +          originate: +            always: true +            metric: 10 +            metric_type: 2 +            route_map: 'ingress' +        mpls_te: +          enabled: true +          router_address: '192.0.11.11' +        auto_cost: +          reference_bandwidth: 2 +        neighbor: +          - neighbor_id: '192.0.11.12' +            poll_interval: 10 +            priority: 2 +        redistribute: +          - route_type: 'bgp' +            metric: 10 +            metric_type: 2 +        passive_interface: +          - 'eth1' +          - 'eth2' +        parameters: +          router_id: '192.0.1.1' +          opaque_lsa: true +          rfc1583_compatibility: true +          abr_type: 'cisco' +        areas: +          - area_id: '2' +            area_type: +              normal: true +            authentication: "plaintext-password" +            shortcut: 'enable' +          - area_id: '3' +            area_type: +              nssa: +                set: true +          - area_id: '4' +            area_type: +              stub: +                default_cost: 20 +            network: +              - address: '192.0.2.0/24' +            range: +              - address: '192.0.3.0/24' +                cost: 10 +              - address: '192.0.4.0/24' +                cost: 12 +    state: rendered  #  #  # ------------------------- @@ -1302,10 +1298,10 @@ EXAMPLES = """  # Using parsed  #  # -- name: Render the commands for provided  configuration -      vyos.vyos.vyos_ospfv2: -        running_config:  -         "set protocols ospf area 2 area-type 'normal' +- name: Parse the commands for provided  structured configuration +  vyos.vyos.vyos_ospfv2: +    running_config: +      "set protocols ospf area 2 area-type 'normal'   set protocols ospf area 2 authentication 'plaintext-password'   set protocols ospf area 2 shortcut 'enable'   set protocols ospf area 3 area-type 'nssa' @@ -1334,7 +1330,7 @@ EXAMPLES = """   set protocols ospf passive-interface 'eth2'   set protocols ospf redistribute bgp metric '10'   set protocols ospf redistribute bgp metric-type '2'" -        state: parsed +    state: parsed  #  #  # ------------------------- @@ -1473,9 +1469,9 @@ EXAMPLES = """  # set protocols ospf redistribute bgp metric-type '2'  #  - name: Gather ospfv2 routes config with provided configurations -      vyos.vyos.vyos_ospfv2: -          config: -          state: gathered +  vyos.vyos.vyos_ospfv2: +    config: +    state: gathered  #  #  # ------------------------- @@ -1645,178 +1641,10 @@ EXAMPLES = """  # set protocols ospf redistribute bgp metric '10'  # set protocols ospf redistribute bgp metric-type '2'  # -- name: Delete single attributes of ospfv2 routes. -      vyos.vyos.vyos_ospfv2: -        config: -          log_adjacency_changes: 'detail' -          max_metric: -          default_information: -          mpls_te: -          neighbor: -          redistribute: -          parameters: -          passive_interface: -          areas: -        state: deleted -# -# -# ------------------------ -# Module Execution Results -# ------------------------ -# -#    "before": { -#        "areas": [ -#            { -#                "area_id": "2", -#                "area_type": { -#                    "normal": true -#                }, -#                "authentication": "plaintext-password", -#                "shortcut": "enable" -#            }, -#            { -#                "area_id": "3", -#                "area_type": { -#                    "nssa": { -#                        "set": true -#                    } -#                } -#            }, -#            { -#                "area_id": "4", -#                "area_type": { -#                    "stub": { -#                        "default_cost": 20, -#                        "set": true -#                    } -#                }, -#                "network": [ -#                    { -#                        "address": "192.0.2.0/24" -#                    } -#                ], -#                "range": [ -#                    { -#                        "address": "192.0.3.0/24", -#                        "cost": 10 -#                    }, -#                    { -#                        "address": "192.0.4.0/24", -#                        "cost": 12 -#                    } -#                ] -#            } -#        ], -#        "auto_cost": { -#            "reference_bandwidth": 2 -#        }, -#        "default_information": { -#            "originate": { -#                "always": true, -#                "metric": 10, -#                "metric_type": 2, -#                "route_map": "ingress" -#            } -#        }, -#        "log_adjacency_changes": "detail", -#        "max_metric": { -#            "router_lsa": { -#                "administrative": true, -#                "on_shutdown": 10, -#                "on_startup": 10 -#            } -#        }, -#        "mpls_te": { -#            "enabled": true, -#            "router_address": "192.0.11.11" -#        }, -#        "neighbor": [ -#            { -#                "neighbor_id": "192.0.11.12", -#                "poll_interval": 10, -#                "priority": 2 -#            } -#        ], -#        "parameters": { -#            "abr_type": "cisco", -#            "opaque_lsa": true, -#            "rfc1583_compatibility": true, -#            "router_id": "192.0.1.1" -#        }, -#        "passive_interface": [ -#            "eth2", -#            "eth1" -#        ], -#        "redistribute": [ -#            { -#                "metric": 10, -#                "metric_type": 2, -#                "route_type": "bgp" -#            } -#        ] -#    } -# "commands": [ -#        "delete protocols ospf mpls-te",  -#        "delete protocols ospf redistribute",  -#        "delete protocols ospf auto-cost",  -#        "delete protocols ospf passive-interface",  -#        "delete protocols ospf parameters",  -#        "delete protocols ospf default-information",  -#        "delete protocols ospf max-metric",  -#        "delete protocols ospf log-adjacency-changes",  -#        "delete protocols ospf neighbor",  -#        "delete protocols ospf area 2",  -#        "delete protocols ospf area 3",  -#        "delete protocols ospf area 4",  -#        "delete protocols ospf area" -#    ] -# -# "after": [] -# After state -# ------------ -# vyos@192# run show configuration commands | grep ospf - - -# Using deleted -# -# Before state -# ------------- -# -# vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 2 area-type 'normal' -# set protocols ospf area 2 authentication 'plaintext-password' -# set protocols ospf area 2 shortcut 'enable' -# set protocols ospf area 3 area-type 'nssa' -# set protocols ospf area 4 area-type stub default-cost '20' -# set protocols ospf area 4 network '192.0.2.0/24' -# set protocols ospf area 4 range 192.0.3.0/24 cost '10' -# set protocols ospf area 4 range 192.0.4.0/24 cost '12' -# set protocols ospf auto-cost reference-bandwidth '2' -# set protocols ospf default-information originate 'always' -# set protocols ospf default-information originate metric '10' -# set protocols ospf default-information originate metric-type '2' -# set protocols ospf default-information originate route-map 'ingress' -# set protocols ospf log-adjacency-changes 'detail' -# set protocols ospf max-metric router-lsa 'administrative' -# set protocols ospf max-metric router-lsa on-shutdown '10' -# set protocols ospf max-metric router-lsa on-startup '10' -# set protocols ospf mpls-te 'enable' -# set protocols ospf mpls-te router-address '192.0.11.11' -# set protocols ospf neighbor 192.0.11.12 poll-interval '10' -# set protocols ospf neighbor 192.0.11.12 priority '2' -# set protocols ospf parameters abr-type 'cisco' -# set protocols ospf parameters 'opaque-lsa' -# set protocols ospf parameters 'rfc1583-compatibility' -# set protocols ospf parameters router-id '192.0.1.1' -# set protocols ospf passive-interface 'eth1' -# set protocols ospf passive-interface 'eth2' -# set protocols ospf redistribute bgp metric '10' -# set protocols ospf redistribute bgp metric-type '2' -#  - name: Delete attributes of ospfv2 routes. -      vyos.vyos.vyos_ospfv2: -        config: -        state: deleted +  vyos.vyos.vyos_ospfv2: +    config: +    state: deleted  #  #  # ------------------------ @@ -1918,11 +1746,11 @@ EXAMPLES = """  #        "delete protocols ospf"  #    ]  # -# "after": [] +# "after": {}  # After state  # ------------  # vyos@192# run show configuration commands | grep ospf - +#  """  RETURN = """ @@ -1950,8 +1778,12 @@ commands:  from ansible.module_utils.basic import AnsibleModule -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv2.ospfv2 import Ospfv2Args -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import Ospfv2 +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv2.ospfv2 import ( +    Ospfv2Args, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import ( +    Ospfv2, +)  def main(): @@ -1963,6 +1795,7 @@ def main():      required_if = [          ("state", "merged", ("config",)),          ("state", "replaced", ("config",)), +        ("state", "rendered", ("config",)),          ("state", "parsed", ("running_config",)),      ]      mutually_exclusive = [("config", "running_config")] @@ -1977,5 +1810,5 @@ def main():      module.exit_json(**result) -if __name__ == '__main__': +if __name__ == "__main__":      main() diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml deleted file mode 100644 index 150242a..0000000 --- a/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml +++ /dev/null @@ -1,57 +0,0 @@ ---- -- debug: -    msg: Start vyos_ospfv2 deleted integration tests ansible_connection={{ -      ansible_connection }} - -- include_tasks: _populate.yaml - -- block: - -    - name: Delete attributes of ospfv2. -      register: result -      vyos.vyos.vyos_ospfv2: &id001 -        config: -          log_adjacency_changes: 'detail' -          max_metric: -          default_information: -          mpls_te: -          neighbor: -          redistribute: -          parameters: -          passive_interface: -          areas: -        state: deleted - -    - name: Assert that the before dicts were correctly generated -      assert: -        that: -          - "{{ populate == result['before'] }}" - -    - name: Assert that the correct set of commands were generated -      assert: -        that: -          - "{{ deleted_single['commands'] | symmetric_difference(result['commands']) |length\ -            \ == 0 }}" - -    - name: Assert that the after dicts were correctly generated -      assert: -        that: -          - "{{ deleted_single['after'] == result['after'] }}" - -    - name: Delete attributes of given interfaces (IDEMPOTENT) -      register: result -      vyos.vyos.vyos_ospfv2: *id001 - -    - name: Assert that the previous task was idempotent -      assert: -        that: -          - result.changed == false -          - result.commands|length == 0 - -    - name: Assert that the before dicts were correctly generated -      assert: -        that: -          - "{{ deleted_single['after'] == result['before'] }}" -  always: - -    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml index 22c378b..bc5e1e2 100644 --- a/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml @@ -9,9 +9,9 @@  - block: -    - name: Merge the provided configuration with the exisiting running configuration +    - name: Gather the provided configuration with the exisiting running configuration        register: result -      vyos.vyos.vyos_ospfv2: &id001 +      vyos.vyos.vyos_ospfv2:          config:          state: gathered @@ -19,15 +19,6 @@        assert:          that:            - "{{ populate  == result['gathered'] }}" - -    - name: Gather the existing running configuration (IDEMPOTENT) -      register: result -      vyos.vyos.vyos_ospfv2: *id001 - -    - name: Assert that the previous task was idempotent -      assert: -        that: -          - result['changed'] == false    always:      - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/merged_update.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/merged_update.yaml index 453dbb0..9b6823c 100644 --- a/tests/integration/targets/vyos_ospfv2/tests/cli/merged_update.yaml +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/merged_update.yaml @@ -67,4 +67,4 @@            - "{{ merged_update['after'] == result['before'] }}"    always: -    - include_tasks: _remove_config.yaml
\ No newline at end of file +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml index 6fbe2f9..cfa29f9 100644 --- a/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml @@ -3,39 +3,13 @@      msg: START vyos_ospfv2 parsed integration tests on connection={{ ansible_connection        }} -- include_tasks: _remove_config.yaml - -- include_tasks: _populate.yaml - -- block: - -    - name: Gather ospfv2 facts -      register: ospfv2_facts -      vyos.vyos.vyos_facts: -        gather_subset: -          - default -        gather_network_resources: -          - ospfv2 - -    - name: Provide the running configuration for parsing (config to be parsed) -      register: result -      vyos.vyos.vyos_ospfv2: &id001 -        running_config: "{{ lookup('file', '_parsed_config.cfg') }}" -        state: parsed - -    - name: Assert that correct parsing done -      assert: -        that: "{{ ansible_facts['network_resources']['ospfv2'] == result['parsed']\ -          \ }}" - -    - name: Gather the existing running configuration (IDEMPOTENT) -      register: result -      vyos.vyos.vyos_ospfv2: *id001 - -    - name: Assert that the previous task was idempotent -      assert: -        that: -          - result['changed'] == false -  always: - -    - include_tasks: _remove_config.yaml +- name: Parse externally provided ospfv2 config to agnostic model +  register: result +  vyos.vyos.vyos_ospfv2: +    running_config: "{{ lookup('file', '_parsed_config.cfg') }}" +    state: parsed + +- name: Assert that config was correctly parsed +  assert: +    that: +      - "{{ parsed['after'] == result['parsed'] }}" diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml index 86c07cf..8a805a6 100644 --- a/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml @@ -5,13 +5,11 @@  - include_tasks: _remove_config.yaml -- include_tasks: _populate.yaml -  - block:      - name: Structure provided configuration into device specific commands        register: result -      vyos.vyos.vyos_ospfv2: &id001 +      vyos.vyos.vyos_ospfv2:          config:            log_adjacency_changes: 'detail'            max_metric: @@ -74,15 +72,5 @@          that:            - "{{ rendered['commands'] | symmetric_difference(result['rendered'])\              \ |length == 0 }}" - -    - name: Structure provided configuration into device specific commands (IDEMPOTENT) -      register: result -      vyos.vyos.vyos_ospfv2: *id001 - -    - name: Assert that the previous task was idempotent -      assert: -        that: -          - result['changed'] == false -  always: - -    - include_tasks: _remove_config.yaml +- debug: +    msg: END vyos_ospfv2 rendered integration tests on connection={{ ansible_connection }} diff --git a/tests/integration/targets/vyos_ospfv2/vars/main.yaml b/tests/integration/targets/vyos_ospfv2/vars/main.yaml index 76a54e3..e55da20 100644 --- a/tests/integration/targets/vyos_ospfv2/vars/main.yaml +++ b/tests/integration/targets/vyos_ospfv2/vars/main.yaml @@ -1,6 +1,6 @@  ---  merged: -  before: [] +  before: {}    commands:      - set protocols ospf mpls-te enable      - set protocols ospf mpls-te router-address '192.0.11.11' @@ -39,63 +39,6 @@ merged:      - set protocols ospf area '4'      - set protocols ospf area 4 network 192.0.2.0/24    after: -      areas: -        - area_id: '2' -          area_type: -            normal: true -          authentication: "plaintext-password" -          shortcut: 'enable' -        - area_id: '3' -          area_type: -            nssa: -              set: true -        - area_id: '4' -          area_type: -            stub: -              default_cost: 20 -              set: true -          network: -            - address: '192.0.2.0/24' -          range: -            - address: '192.0.3.0/24' -              cost: 10 -            - address: '192.0.4.0/24' -              cost: 12 -      auto_cost: -        reference_bandwidth: 2 -      default_information: -        originate: -          always: true -          metric: 10 -          metric_type: 2 -          route_map: 'ingress' -      log_adjacency_changes: 'detail' -      max_metric: -        router_lsa: -          administrative: true -          on_shutdown: 10 -          on_startup: 10 -      mpls_te: -        enabled: true -        router_address: '192.0.11.11' -      neighbor: -        - neighbor_id: '192.0.11.12' -          poll_interval: 10 -          priority: 2 -      parameters: -        abr_type: 'cisco' -        opaque_lsa: true -        rfc1583_compatibility: true -        router_id: '192.0.1.1' -      passive_interface: -        - 'eth2' -        - 'eth1' -      redistribute: -        - metric: 10 -          metric_type: 2 -          route_type: 'bgp' -merged_update: -  before:      areas:        - area_id: '2'          area_type: @@ -145,13 +88,14 @@ merged_update:        rfc1583_compatibility: true        router_id: '192.0.1.1'      passive_interface: -      - 'eth2'        - 'eth1' +      - 'eth2'      redistribute:        - metric: 10          metric_type: 2          route_type: 'bgp' -  after: +merged_update: +  before:      areas:        - area_id: '2'          area_type: @@ -163,10 +107,12 @@ merged_update:            nssa:              set: true        - area_id: '4' +        area_type: +          stub: +            default_cost: 20 +            set: true          network:            - address: '192.0.2.0/24' -          - address: '192.0.22.0/24' -          - address: '192.0.32.0/24'          range:            - address: '192.0.3.0/24'              cost: 10 @@ -199,17 +145,13 @@ merged_update:        rfc1583_compatibility: true        router_id: '192.0.1.1'      passive_interface: -      - 'eth2'        - 'eth1' +      - 'eth2'      redistribute:        - metric: 10          metric_type: 2          route_type: 'bgp' -  commands: -    - delete protocols ospf area 4 area-type stub -    - set protocols ospf area 4 network 192.0.22.0/24 -    - set protocols ospf area 4 network 192.0.32.0/24 -populate: +  after:      areas:        - area_id: '2'          area_type: @@ -221,12 +163,10 @@ populate:            nssa:              set: true        - area_id: '4' -        area_type: -          stub: -            default_cost: 20 -            set: true          network:            - address: '192.0.2.0/24' +          - address: '192.0.22.0/24' +          - address: '192.0.32.0/24'          range:            - address: '192.0.3.0/24'              cost: 10 @@ -259,12 +199,72 @@ populate:        rfc1583_compatibility: true        router_id: '192.0.1.1'      passive_interface: -      - 'eth2'        - 'eth1' +      - 'eth2'      redistribute:        - metric: 10          metric_type: 2          route_type: 'bgp' +  commands: +    - delete protocols ospf area 4 area-type stub +    - set protocols ospf area 4 network 192.0.22.0/24 +    - set protocols ospf area 4 network 192.0.32.0/24 +populate: +  areas: +    - area_id: '2' +      area_type: +        normal: true +      authentication: "plaintext-password" +      shortcut: 'enable' +    - area_id: '3' +      area_type: +        nssa: +          set: true +    - area_id: '4' +      area_type: +        stub: +          default_cost: 20 +          set: true +      network: +        - address: '192.0.2.0/24' +      range: +        - address: '192.0.3.0/24' +          cost: 10 +        - address: '192.0.4.0/24' +          cost: 12 +  auto_cost: +    reference_bandwidth: 2 +  default_information: +    originate: +      always: true +      metric: 10 +      metric_type: 2 +      route_map: 'ingress' +  log_adjacency_changes: 'detail' +  max_metric: +    router_lsa: +      administrative: true +      on_shutdown: 10 +      on_startup: 10 +  mpls_te: +    enabled: true +    router_address: '192.0.11.11' +  neighbor: +    - neighbor_id: '192.0.11.12' +      poll_interval: 10 +      priority: 2 +  parameters: +    abr_type: 'cisco' +    opaque_lsa: true +    rfc1583_compatibility: true +    router_id: '192.0.1.1' +  passive_interface: +    - 'eth1' +    - 'eth2' +  redistribute: +    - metric: 10 +      metric_type: 2 +      route_type: 'bgp'  replaced:    commands:      - delete protocols ospf passive-interface eth2 @@ -280,57 +280,57 @@ replaced:      - set protocols ospf area 4 network 192.0.22.0/24      - set protocols ospf area 4 network 192.0.32.0/24    after: -      areas: -        - area_id: '2' -          area_type: -            normal: true -          authentication: "plaintext-password" -          shortcut: 'enable' -        - area_id: '4' -          area_type: -            stub: -              default_cost: 20 -              set: true -          network: -            - address: '192.0.12.0/24' -            - address: '192.0.2.0/24' -            - address: '192.0.22.0/24' -            - address: '192.0.32.0/24' -          range: -            - address: '1.1.2.0/24' -              cost: 10 -      auto_cost: -        reference_bandwidth: 2 -      default_information: -        originate: -          always: true -          metric: 10 -          metric_type: 2 -          route_map: 'ingress' -      log_adjacency_changes: 'detail' -      max_metric: -        router_lsa: -          administrative: true -          on_shutdown: 10 -          on_startup: 10 -      mpls_te: -        enabled: true -        router_address: '192.0.22.22' -      neighbor: -        - neighbor_id: '192.0.11.12' -          poll_interval: 10 -          priority: 2 -      parameters: -        abr_type: 'cisco' -        opaque_lsa: true -        rfc1583_compatibility: true -        router_id: '192.0.1.1' -      passive_interface: -        - 'eth1' -      redistribute: -        - metric: 10 -          metric_type: 2 -          route_type: 'bgp' +    areas: +      - area_id: '2' +        area_type: +          normal: true +        authentication: "plaintext-password" +        shortcut: 'enable' +      - area_id: '4' +        area_type: +          stub: +            default_cost: 20 +            set: true +        network: +          - address: '192.0.12.0/24' +          - address: '192.0.2.0/24' +          - address: '192.0.22.0/24' +          - address: '192.0.32.0/24' +        range: +          - address: '1.1.2.0/24' +            cost: 10 +    auto_cost: +      reference_bandwidth: 2 +    default_information: +      originate: +        always: true +        metric: 10 +        metric_type: 2 +        route_map: 'ingress' +    log_adjacency_changes: 'detail' +    max_metric: +      router_lsa: +        administrative: true +        on_shutdown: 10 +        on_startup: 10 +    mpls_te: +      enabled: true +      router_address: '192.0.22.22' +    neighbor: +      - neighbor_id: '192.0.11.12' +        poll_interval: 10 +        priority: 2 +    parameters: +      abr_type: 'cisco' +      opaque_lsa: true +      rfc1583_compatibility: true +      router_id: '192.0.1.1' +    passive_interface: +      - 'eth1' +    redistribute: +      - metric: 10 +        metric_type: 2 +        route_type: 'bgp'  rendered:    commands:      - set protocols ospf mpls-te enable @@ -369,26 +369,67 @@ rendered:      - set protocols ospf area 4 area-type stub default-cost 20      - set protocols ospf area '4'      - set protocols ospf area 4 network 192.0.2.0/24 -deleted_single: -  commands: -    - delete protocols ospf mpls-te -    - delete protocols ospf redistribute -    - delete protocols ospf auto-cost -    - delete protocols ospf passive-interface -    - delete protocols ospf parameters -    - delete protocols ospf default-information -    - delete protocols ospf max-metric -    - delete protocols ospf log-adjacency-changes -    - delete protocols ospf neighbor -    - delete protocols ospf area 2 -    - delete protocols ospf area 3 -    - delete protocols ospf area 4 -    - delete protocols ospf area -  after: [] +parsed: +  after: +    areas: +      - area_id: '2' +        area_type: +          normal: true +        authentication: "plaintext-password" +        shortcut: 'enable' +      - area_id: '3' +        area_type: +          nssa: +            set: true +      - area_id: '4' +        area_type: +          stub: +            default_cost: 20 +            set: true +        network: +          - address: '192.0.2.0/24' +        range: +          - address: '192.0.3.0/24' +            cost: 10 +          - address: '192.0.4.0/24' +            cost: 12 +    auto_cost: +      reference_bandwidth: 2 +    default_information: +      originate: +        always: true +        metric: 10 +        metric_type: 2 +        route_map: 'ingress' +    log_adjacency_changes: 'detail' +    max_metric: +      router_lsa: +        administrative: true +        on_shutdown: 10 +        on_startup: 10 +    mpls_te: +      enabled: true +      router_address: '192.0.11.11' +    neighbor: +      - neighbor_id: '192.0.11.12' +        poll_interval: 10 +        priority: 2 +    parameters: +      abr_type: 'cisco' +      opaque_lsa: true +      rfc1583_compatibility: true +      router_id: '192.0.1.1' +    passive_interface: +      - 'eth1' +      - 'eth2' +    redistribute: +      - metric: 10 +        metric_type: 2 +        route_type: 'bgp'  deleted:    commands:      - 'delete protocols ospf' -  after: [] +  after: {}  round_trip:    after:      areas: diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv2.py b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py index 8e6b095..b825066 100644 --- a/tests/unit/modules/network/vyos/test_vyos_ospfv2.py +++ b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py @@ -71,7 +71,7 @@ class TestVyosFirewallRulesModule(TestVyosModule):          self.mock_get_config.stop()          self.mock_load_config.stop()          self.mock_execute_show_command.stop() -     +      def load_fixtures(self, commands=None, transport="cli", filename=None):          if filename is None:              filename = "vyos_ospfv2_config.cfg" @@ -87,27 +87,23 @@ class TestVyosFirewallRulesModule(TestVyosModule):              dict(                  config=dict(                      log_adjacency_changes="detail", -                    mpls_te=dict(enabled=True, router_address='192.0.11.11'), +                    mpls_te=dict(enabled=True, router_address="192.0.11.11"),                      auto_cost=dict(reference_bandwidth=2),                      areas=[                          dict(                              area_id="2",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="4", -                            area_type=dict( -                                stub=dict(default_cost=10) -                            ), -                            network=[ -                                dict(address="192.0.2.0/24"), -                            ], +                            area_type=dict(stub=dict(default_cost=10)), +                            network=[dict(address="192.0.2.0/24"),],                              range=[                                  dict(address="192.0.3.0/24", cost=10), -                                dict(address="192.0.4.0/24", cost=12) -                            ] +                                dict(address="192.0.4.0/24", cost=12), +                            ],                          ),                      ],                  ), @@ -115,21 +111,21 @@ class TestVyosFirewallRulesModule(TestVyosModule):              )          )          commands = [ -          "set protocols ospf mpls-te enable", -          "set protocols ospf mpls-te router-address '192.0.11.11'", -          "set protocols ospf auto-cost reference-bandwidth '2'", -          "set protocols ospf log-adjacency-changes 'detail'", -          "set protocols ospf area '2'", -          "set protocols ospf area 2 authentication plaintext-password", -          "set protocols ospf area 2 shortcut enable", -          "set protocols ospf area 2 area-type normal", -          "set protocols ospf area 4 range 192.0.3.0/24 cost 10", -          "set protocols ospf area 4 range 192.0.3.0/24", -          "set protocols ospf area 4 range 192.0.4.0/24 cost 12", -          "set protocols ospf area 4 range 192.0.4.0/24", -          "set protocols ospf area 4 area-type stub default-cost 10", -          "set protocols ospf area '4'", -          "set protocols ospf area 4 network 192.0.2.0/24" +            "set protocols ospf mpls-te enable", +            "set protocols ospf mpls-te router-address '192.0.11.11'", +            "set protocols ospf auto-cost reference-bandwidth '2'", +            "set protocols ospf log-adjacency-changes 'detail'", +            "set protocols ospf area '2'", +            "set protocols ospf area 2 authentication plaintext-password", +            "set protocols ospf area 2 shortcut enable", +            "set protocols ospf area 2 area-type normal", +            "set protocols ospf area 4 range 192.0.3.0/24 cost 10", +            "set protocols ospf area 4 range 192.0.3.0/24", +            "set protocols ospf area 4 range 192.0.4.0/24 cost 12", +            "set protocols ospf area 4 range 192.0.4.0/24", +            "set protocols ospf area 4 area-type stub default-cost 10", +            "set protocols ospf area '4'", +            "set protocols ospf area 4 network 192.0.2.0/24",          ]          self.execute_module(changed=True, commands=commands) @@ -142,20 +138,16 @@ class TestVyosFirewallRulesModule(TestVyosModule):                              area_id="12",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="14", -                            area_type=dict( -                                stub=dict(default_cost=20) -                            ), -                            network=[ -                                dict(address="192.0.12.0/24"), -                            ], +                            area_type=dict(stub=dict(default_cost=20)), +                            network=[dict(address="192.0.12.0/24"),],                              range=[                                  dict(address="192.0.13.0/24", cost=10), -                                dict(address="192.0.14.0/24", cost=12) -                            ] +                                dict(address="192.0.14.0/24", cost=12), +                            ],                          ),                      ],                  ), @@ -173,21 +165,19 @@ class TestVyosFirewallRulesModule(TestVyosModule):                              area_id="12",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="14", -                            area_type=dict( -                                stub=dict(set=False) -                            ), +                            area_type=dict(stub=dict(set=False)),                              network=[                                  dict(address="192.0.12.0/24"),                                  dict(address="192.0.22.0/24"),                              ],                              range=[                                  dict(address="192.0.13.0/24", cost=10), -                                dict(address="192.0.14.0/24", cost=12) -                            ] +                                dict(address="192.0.14.0/24", cost=12), +                            ],                          ),                      ],                  ), @@ -196,7 +186,7 @@ class TestVyosFirewallRulesModule(TestVyosModule):          )          commands = [              "delete protocols ospf area 14 area-type stub", -            "set protocols ospf area 14 network 192.0.22.0/24" +            "set protocols ospf area 14 network 192.0.22.0/24",          ]          self.execute_module(changed=True, commands=commands) @@ -205,28 +195,24 @@ class TestVyosFirewallRulesModule(TestVyosModule):              dict(                  config=dict(                      log_adjacency_changes="detail", -                    mpls_te=dict(enabled=True, router_address='192.0.11.11'), +                    mpls_te=dict(enabled=True, router_address="192.0.11.11"),                      auto_cost=dict(reference_bandwidth=2),                      areas=[                          dict(                              area_id="12",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="15", -                            area_type=dict( -                                stub=dict(default_cost=10) -                            ), -                            network=[ -                                dict(address="192.0.12.0/24"), -                            ], +                            area_type=dict(stub=dict(default_cost=10)), +                            network=[dict(address="192.0.12.0/24"),],                              range=[                                  dict(address="192.0.13.0/24", cost=10),                                  dict(address="192.0.14.0/24", cost=12), -                                dict(address="192.0.15.0/24", cost=14) -                            ] +                                dict(address="192.0.15.0/24", cost=14), +                            ],                          ),                      ],                  ), @@ -247,7 +233,7 @@ class TestVyosFirewallRulesModule(TestVyosModule):              "set protocols ospf area 15 range 192.0.15.0/24",              "set protocols ospf area 15 area-type stub default-cost 10",              "set protocols ospf area '15'", -            "set protocols ospf area 15 network 192.0.12.0/24" +            "set protocols ospf area 15 network 192.0.12.0/24",          ]          self.execute_module(changed=True, commands=commands) @@ -260,20 +246,16 @@ class TestVyosFirewallRulesModule(TestVyosModule):                              area_id="12",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="14", -                            area_type=dict( -                                stub=dict(default_cost=20) -                            ), -                            network=[ -                                dict(address="192.0.12.0/24"), -                            ], +                            area_type=dict(stub=dict(default_cost=20)), +                            network=[dict(address="192.0.12.0/24"),],                              range=[                                  dict(address="192.0.13.0/24", cost=10), -                                dict(address="192.0.14.0/24", cost=12) -                            ] +                                dict(address="192.0.14.0/24", cost=12), +                            ],                          ),                      ],                  ), @@ -287,63 +269,30 @@ class TestVyosFirewallRulesModule(TestVyosModule):          commands = ["delete protocols ospf"]          self.execute_module(changed=True, commands=commands) -    def test_vyos_ospfv2_set_01_deleted_single_attributes(self): -        set_module_args( -            dict( -                config=dict( -                    mpls_te=dict(), -                    auto_cost=dict(), -                    areas=[] -                ), -                state="deleted", -            ) -        ) -        commands = ["delete protocols ospf area 12", -                    "delete protocols ospf area 14", -                    "delete protocols ospf area"] -        self.execute_module(changed=True, commands=commands) -      def test_vyos_ospfv2_gathered(self):          set_module_args(dict(state="gathered"))          result = self.execute_module(              changed=False, filename="vyos_ospfv2_config.cfg"          )          gather_dict = { -              "areas": [ -                  { -                      "area_id": "2", -                      "area_type": { -                          "normal": True -                      }, -                      "authentication": "plaintext-password", -                      "shortcut": "enable" -                  }, -                  { -                      "area_id": "14", -                      "area_type": { -                          "stub": { -                              "default_cost": 20, -                              "set": True -                          } -                      }, -                      "network": [ -                          { -                              "address": "192.0.12.0/24" -                          } -                      ], -                      "range": [ -                          { -                              "address": "192.0.13.0/24", -                              "cost": 10 -                          }, -                          { -                              "address": "192.0.14.0/24", -                              "cost": 12 -                          } -                      ] -                  } -              ], -          } +            "areas": [ +                { +                    "area_id": "2", +                    "area_type": {"normal": True}, +                    "authentication": "plaintext-password", +                    "shortcut": "enable", +                }, +                { +                    "area_id": "14", +                    "area_type": {"stub": {"default_cost": 20, "set": True}}, +                    "network": [{"address": "192.0.12.0/24"}], +                    "range": [ +                        {"address": "192.0.13.0/24", "cost": 10}, +                        {"address": "192.0.14.0/24", "cost": 12}, +                    ], +                }, +            ], +        }          self.assertEqual(sorted(gather_dict), sorted(result["gathered"]))      def test_vyos_ospfv2_parsed(self): @@ -382,54 +331,28 @@ set protocols ospf redistribute bgp metric-type '2'"""              "areas": [                  {                      "area_id": "2", -                    "area_type": { -                        "normal": True -                    }, +                    "area_type": {"normal": True},                      "authentication": "plaintext-password", -                    "shortcut": "enable" -                }, -                { -                    "area_id": "3", -                    "area_type": { -                        "nssa": { -                            "set": True -                        } -                    } +                    "shortcut": "enable",                  }, +                {"area_id": "3", "area_type": {"nssa": {"set": True}}},                  {                      "area_id": "4", -                    "area_type": { -                        "stub": { -                            "default_cost": 20, -                            "set": True -                        } -                    }, -                    "network": [ -                        { -                            "address": "192.0.2.0/24" -                        } -                    ], +                    "area_type": {"stub": {"default_cost": 20, "set": True}}, +                    "network": [{"address": "192.0.2.0/24"}],                      "range": [ -                        { -                            "address": "192.0.3.0/24", -                            "cost": 10 -                        }, -                        { -                            "address": "192.0.4.0/24", -                            "cost": 12 -                        } -                    ] -                } +                        {"address": "192.0.3.0/24", "cost": 10}, +                        {"address": "192.0.4.0/24", "cost": 12}, +                    ], +                },              ], -            "auto_cost": { -                "reference_bandwidth": 2 -            }, +            "auto_cost": {"reference_bandwidth": 2},              "default_information": {                  "originate": {                      "always": True,                      "metric": 10,                      "metric_type": 2, -                    "route_map": "ingress" +                    "route_map": "ingress",                  }              },              "log_adjacency_changes": "detail", @@ -437,37 +360,27 @@ set protocols ospf redistribute bgp metric-type '2'"""                  "router_lsa": {                      "administrative": True,                      "on_shutdown": 10, -                    "on_startup": 10 +                    "on_startup": 10,                  }              }, -            "mpls_te": { -                "enabled": True, -                "router_address": "192.0.11.11" -            }, +            "mpls_te": {"enabled": True, "router_address": "192.0.11.11"},              "neighbor": [                  {                      "neighbor_id": "192.0.11.12",                      "poll_interval": 10, -                    "priority": 2 +                    "priority": 2,                  }              ],              "parameters": {                  "abr_type": "cisco",                  "opaque_lsa": True,                  "rfc1583_compatibility": True, -                "router_id": "192.0.1.1" +                "router_id": "192.0.1.1",              }, -            "passive_interface": [ -                "eth2", -                "eth1" -            ], +            "passive_interface": ["eth2", "eth1"],              "redistribute": [ -                { -                    "metric": 10, -                    "metric_type": 2, -                    "route_type": "bgp" -                } -            ] +                {"metric": 10, "metric_type": 2, "route_type": "bgp"} +            ],          }          self.assertEqual(sorted(parsed_list), sorted(result["parsed"])) @@ -476,27 +389,23 @@ set protocols ospf redistribute bgp metric-type '2'"""              dict(                  config=dict(                      log_adjacency_changes="detail", -                    mpls_te=dict(enabled=True, router_address='192.0.11.11'), +                    mpls_te=dict(enabled=True, router_address="192.0.11.11"),                      auto_cost=dict(reference_bandwidth=2),                      areas=[                          dict(                              area_id="2",                              area_type=dict(normal=True),                              authentication="plaintext-password", -                            shortcut='enable', +                            shortcut="enable",                          ),                          dict(                              area_id="4", -                            area_type=dict( -                                stub=dict(default_cost=10) -                            ), -                            network=[ -                                dict(address="192.0.2.0/24"), -                            ], +                            area_type=dict(stub=dict(default_cost=10)), +                            network=[dict(address="192.0.2.0/24"),],                              range=[                                  dict(address="192.0.3.0/24", cost=10), -                                dict(address="192.0.4.0/24", cost=12) -                            ] +                                dict(address="192.0.4.0/24", cost=12), +                            ],                          ),                      ],                  ), @@ -518,7 +427,7 @@ set protocols ospf redistribute bgp metric-type '2'"""              "set protocols ospf area 4 range 192.0.4.0/24",              "set protocols ospf area 4 area-type stub default-cost 10",              "set protocols ospf area '4'", -            "set protocols ospf area 4 network 192.0.2.0/24" +            "set protocols ospf area 4 network 192.0.2.0/24",          ]          result = self.execute_module(changed=False)          self.assertEqual( diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py index e0ab699..49d4652 100644 --- a/tests/unit/modules/network/vyos/vyos_module.py +++ b/tests/unit/modules/network/vyos/vyos_module.py @@ -60,7 +60,7 @@ class TestVyosModule(ModuleTestCase):          commands=None,          sort=True,          defaults=False, -        filename=None +        filename=None,      ):          self.load_fixtures(commands) | 
