diff options
26 files changed, 3817 insertions, 1158 deletions
| diff --git a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py index 1b11d3c..a2a6e04 100644 --- a/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/argspec/ospfv2/ospfv2.py @@ -34,7 +34,6 @@ class Ospfv2Args(object):  # pylint: disable=R0903      argument_spec = {          'config': { -            'elements': 'dict',              'options': {                  'auto_cost': {                      'options': { @@ -140,10 +139,10 @@ class Ospfv2Args(object):  # pylint: disable=R0903                      },                      'type': 'list'                  }, -                'ospf_area': { +                'areas': {                      'elements': 'dict',                      'options': { -                        'area': { +                        'area_id': {                              'type': 'str'                          },                          'area_type': { @@ -159,6 +158,9 @@ class Ospfv2Args(object):  # pylint: disable=R0903                                          'no_summary': {                                              'type': 'bool'                                          }, +                                        'set': { +                                            'type': 'bool' +                                        },                                          'translate': {                                              'choices':                                              ['always', 'candidate', 'never'], @@ -175,6 +177,9 @@ class Ospfv2Args(object):  # pylint: disable=R0903                                          },                                          'no_summary': {                                              'type': 'bool' +                                        }, +                                        'set': { +                                            'type': 'bool'                                          }                                      },                                      'type': 'dict' @@ -227,6 +232,7 @@ class Ospfv2Args(object):  # pylint: disable=R0903                                  'authentication': {                                      'options': {                                          'md5': { +                                            'elements': 'dict',                                              'options': {                                                  'key_id': {                                                      'type': 'int' @@ -235,7 +241,7 @@ class Ospfv2Args(object):  # pylint: disable=R0903                                                      'type': 'str'                                                  }                                              }, -                                            'type': 'dict' +                                            'type': 'list'                                          },                                          'plaintext_password': {                                              'type': 'str' @@ -343,7 +349,7 @@ class Ospfv2Args(object):  # pylint: disable=R0903                      'type': 'dict'                  }              }, -            'type': 'list' +            'type': 'dict'          },          "running_config": {"type": "str"},          'state': { diff --git a/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py index 0109ca1..13645cd 100644 --- a/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/config/ospfv2/ospfv2.py @@ -29,19 +29,16 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils      list_diff_want_only, _in_target, _is_w_same, _bool_to_str  ) +  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) @@ -52,7 +49,10 @@ class Ospfv2(ConfigBase):          :rtype: A dictionary          :returns: The current configuration as a dictionary          """ -        facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data) + +        (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 [] @@ -64,6 +64,7 @@ class Ospfv2(ConfigBase):          :rtype: A dictionary          :returns: The result from module execution          """ +          result = {'changed': False}          warnings = list()          commands = list() @@ -73,41 +74,38 @@ class Ospfv2(ConfigBase):          else:              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 = []          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): @@ -118,6 +116,7 @@ class Ospfv2(ConfigBase):          :returns: the commands necessary to migrate the current configuration                    to the desired configuration          """ +          want = self._module.params['config']          have = existing_ospfv2_facts          resp = self.set_state(want, have) @@ -132,24 +131,18 @@ class Ospfv2(ConfigBase):          :returns: the commands necessary to migrate the current configuration                    to the desired configuration          """ +          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 == "overridden": -            commands.extend(self._state_overridden(w, h)) -        elif self.state == "deleted": +        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 w: -            if self.state == "merged" or self.state == "rendered": -                for w_item in w: -                    commands.extend(self._state_merged(w_item, h)) -            elif self.state == "replaced": -                for w_item in w: -                    commands.extend(self._state_replaced(w_item, h)) +        elif self.state in ('merged', 'rendered'): +            commands.extend(self._state_merged(w, h)) +        elif self.state == 'replaced': +            commands.extend(self._state_replaced(w, h))          return commands      def search_obj_in_have(self, have, w_name, key): @@ -160,6 +153,7 @@ class Ospfv2(ConfigBase):          :param type: rule_sets/rule/r_list.          :return: rule-set/rule.          """ +          if have:              for item in have:                  if item[key] == w_name[key]: @@ -173,12 +167,12 @@ class Ospfv2(ConfigBase):          :returns: the commands necessary to migrate the current configuration                    to the desired configuration          """ +          commands = [] -        h_item = {}          if have: -            h_item = have[0] -            commands.extend(self._render_ospf_param(h_item, want, opr=False)) -        commands.extend(self._render_ospf_param(want, h_item)) +            commands.extend(self._render_ospf_param(have, want, +                            opr=False)) +        commands.extend(self._render_ospf_param(want, have))          return commands      def _state_merged(self, want, have): @@ -188,11 +182,9 @@ class Ospfv2(ConfigBase):          :returns: the commands necessary to merge the provided into                    the current configuration          """ +          commands = [] -        h_item = {} -        if have: -            h_item = have[0] -        commands.extend(self._render_ospf_param(want, h_item)) +        commands.extend(self._render_ospf_param(want, have))          return commands      def _state_deleted(self, want, have): @@ -202,18 +194,27 @@ class Ospfv2(ConfigBase):          :returns: the commands necessary to remove the current configuration                    of the provided objects          """ +          commands = [] -        if want: -            for w in want: -                if have: -                    h = have[0] -                    if h: -                        for key, val in iteritems(w): -                            if key in h: -                                if key == 'ospf_area': -                                    key = 'area' -                                commands.append(self._compute_command(attr=key, opr=False)) -        elif have and have[0]: +        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')          return commands @@ -227,16 +228,15 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated commands list.          """ +          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): +            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))                  else: @@ -253,21 +253,25 @@ class Ospfv2(ConfigBase):          :param opr: operation.          :return: list of commands.          """ +          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 == "ospf_area": -            commands.extend(self._render_ospf_area(key, w, h, opr=opr)) -        elif key == "timers": -            commands.extend(self._render_timers(key, w, h, opr=opr, remove=remove)) -        elif key == "distance": -            commands.extend(self._render_distance(key, w, h, opr=opr, remove=remove)) +        elif key == 'areas': +            commands.extend(self._render_areas(key, w, h, opr=opr)) +        elif key == 'timers': +            commands.extend(self._render_timers(key, w, h, opr=opr)) +        elif key == 'distance': +            commands.extend(self._render_distance(key, w, h, opr=opr))          return commands      def _render_dict_param(self, attr, want, have, opr=True): @@ -279,6 +283,7 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated list of commands.          """ +          commands = []          h = {}          if have: @@ -288,18 +293,19 @@ class Ospfv2(ConfigBase):          elif want[attr]:              leaf_dict = {'auto_cost': 'reference_bandwidth',                           'mpls_te': ('enabled', 'router_address'), -                         'parameters': ("router_id", "abr_type", "opaque_lsa", "rfc1583_compatibility")} +                         'parameters': ('router_id', 'abr_type', +                         'opaque_lsa', 'rfc1583_compatibility')}              leaf = leaf_dict[attr] -            for item, value in iteritems(want[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": +                    if item == 'enabled':                          item = 'enable' -                    if item in ("opaque_lsa", "enable", "rfc1583_compatibility"): +                    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))                  elif not opr and item in leaf and not _in_target(h, item): -                    if item == "enabled": +                    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)) @@ -315,6 +321,7 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated list of commands.          """ +          commands = []          h = []          if want: @@ -327,7 +334,7 @@ class Ospfv2(ConfigBase):              if opr:                  members = list_diff_want_only(w, h)                  for member in members: -                    command = cmd + attr.replace("_","-") + " " +                    command = cmd + attr.replace('_', '-') + ' '                      if attr == 'network':                          command += member['address']                      else: @@ -338,11 +345,96 @@ class Ospfv2(ConfigBase):                      for member in w:                          if attr == 'network':                              if not self.search_obj_in_have(h, member, 'address'): -                                commands.append(cmd + attr.replace("_","-") + ' ' + 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): +        """ +        This function forms the set/delete commands based on the 'opr' type +        for attributes with in desired list of dictionary. +        :param attr: attribute name. +        :param w: the desired config. +        :param h: the target config. +        :param cmd: commands to be prepend. +        :param opr: True/False. +        :return: generated commands list. +        """ + +        commands = [] +        h = [] +        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('_', '-')) +        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)) +                        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)) +                        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, +                            )) +        return commands + +    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. +        :param attr: attribute name. +        :param w: the desired config. +        :param h: the target config. +        :param cmd: commands to be prepend. +        :param opr: True/False. +        :return: generated commands list. +        """ + +        commands = [] +        h = [] + +        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))          return commands      def _render_list_dict_param(self, attr, want, have, cmd=None, opr=True): @@ -356,17 +448,24 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated commands list.          """ +          commands = []          h = [] -        name = {'redistribute': 'route_type', -                'neighbor': 'neighbor_id', -                'range': 'address', -                'vlink': 'address'} -        leaf_dict = {'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") -                     } +        name = { +            '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'), +            }          leaf = leaf_dict[attr]          w = want.get(attr) or []          if have: @@ -375,26 +474,43 @@ class Ospfv2(ConfigBase):              commands.append(self._compute_command(attr=attr, opr=opr))          elif w:              for w_item in w: -                for key, val in iteritems(w_item): +                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 == '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 in ('route_type', 'neighbor_id', 'address'): +                        if key in ('route_type', 'neighbor_id', +                                   'address', 'key_id'):                              commands.append(cmd + attr + ' ' + str(val)) -                        elif key == 'authentication': -                            commands.append(self._render_vlink(key, w_item, h_item, cmd, opr)) +                        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'): +                            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): @@ -408,13 +524,12 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated commands list.          """ +          commands = []          attr_dict = {'default_information': 'originate', -                     'max_metric': 'router_lsa', -                     } -        leaf_dict = {'default_information': ("always", "metric", "metric_type", "route_map"), -                    'max_metric': ("always", "metric", "metric_type", "route_map"), -                    } +                     '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: @@ -430,18 +545,24 @@ class Ospfv2(ConfigBase):                  leaf = leaf_dict[attr]                  if h and key in h.keys():                      h_attrib = h.get(key) or {} -                for item, val in iteritems(w[key]): +                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'): -                            commands.append(cmd + (attr.replace("_","-") + " " + key.replace("_","-") + " " + item.replace("_","-"))) -                        else: -                            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 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_ospf_area(self, attr, want, have, opr=True): +    def _render_areas(self, attr, want, have, opr=True):          """          This function forms the set/delete commands based on the 'opr' type          for ospf area attributes. @@ -451,32 +572,38 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated commands list.          """ +          commands = []          h_lst = {}          w_lst = want.get(attr) or [] -        l_set = ("area", "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))          elif w_lst:              for w_area in w_lst: -                cmd = self._compute_command(key='area', attr=_bool_to_str(w_area['area']), opr=opr) + ' ' -                h_area = self.search_obj_in_have(h_lst, w_area, 'area') +                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'], 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): +                    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': -                                commands.append(self._form_attr_cmd(attr=key, val=_bool_to_str(val), opr=opr)) +                            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' 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' and not _in_target(h_area, key): +                            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)) @@ -499,33 +626,61 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated commands list.          """ +          commands = []          h_type = {}          w_type = want.get(attr) or []          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" +            key = 'normal'              if opr and key in w_type.keys() and not _is_w_same(w_type, h_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': ("default_cost", "no_summary", "translate"), -                      'stub': ("default_cost", "no_summary")} +                if not w_type[key] and h_type and h_type[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')}              for key in a_type:                  w_area = want[attr].get(key) or {}                  h_area = {}                  if w_area:                      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): -                            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): -                            commands.append(cmd + (want['area'] + ' ' + attr.replace("_","-") + " " + key + " " + item.replace("_","-"))) +                    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) +                            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) +                            else: +                                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): @@ -537,6 +692,7 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated command.          """ +          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): @@ -548,15 +704,16 @@ class Ospfv2(ConfigBase):          :param opr: True/False.          :return: generated command.          """ +          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("_", "-") -        if val and opr: +            cmd += attr.replace('_', '-') +        if val:              cmd += " '" + str(val) + "'"          return cmd @@ -567,4 +724,6 @@ class Ospfv2(ConfigBase):          :param attrib: attribute          :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/ospfv2/ospfv2.py b/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py index 3457fac..0467b72 100644 --- a/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py +++ b/plugins/module_utils/network/vyos/facts/ospfv2/ospfv2.py @@ -9,19 +9,29 @@ It is in this file the configuration is collected from the device  for a given resource, parsed, and the facts tree is populated  based on the configuration.  """ +from __future__ import absolute_import, division, print_function + +__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  class Ospfv2Facts(object): +      """ The vyos ospfv2 fact class      """ -    def __init__(self, module, subspec='config', options='options'): +    def __init__( +        self, +        module, +        subspec='config', +        options='options', +        ): +          self._module = module          self.argument_spec = Ospfv2Args.argument_spec          spec = deepcopy(self.argument_spec) @@ -46,25 +56,22 @@ class Ospfv2Facts(object):          :rtype: dictionary          :returns: facts          """ +          if not data:              data = self.get_device_data(connection) +              # typically data is populated from the current device configuration              # data = connection.get('show running-config | section ^interface')              # using mock data instead -        objs = [] + +        objs = {}          ospfv2 = findall(r"^set protocols ospf (.+)", data, M)          if ospfv2: -            config = self.render_config(ospfv2) -            if config: -                objs.append(config) -        ansible_facts["ansible_network_resources"].pop("ospfv2", None) +            objs = self.render_config(ospfv2)          facts = {} -        if objs: -            facts["ospfv2"] = [] -            params = utils.validate_config(self.argument_spec, {"config": objs}) -            for cfg in params["config"]: -                facts["ospfv2"].append(utils.remove_empties(cfg)) -        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): @@ -74,37 +81,38 @@ class Ospfv2Facts(object):          :param conf: The configuration          :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["mpls_te"] = self.parse_attrib(conf, "mpls_te", "mpls-te") -        config["default_information"] = self.parse_def_info(conf) -        config["parameters"] = self.parse_attrib(conf, "parameters", "parameters") -        config["route_map"] = self.parse_leaf_list(conf, "route-map") -        config["ospf_area"] = self.parse_attrib_list(conf, "area", "area") -        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, attrib=None): +    def parse_timers(self, conf):          """          This function triggers the parsing of 'timers' attributes          :param conf: configuration -        :param attrib: attribute name          :return: generated config dictionary          """ +          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): @@ -114,6 +122,7 @@ class Ospfv2Facts(object):          :param attrib: 'spf'          :return: generated config dictionary          """ +          cfg_dict = {}          cfg_dict[attrib] = self.parse_attrib(conf, attrib, match=attrib)          return cfg_dict @@ -125,39 +134,9 @@ class Ospfv2Facts(object):          :param attrib: 'refresh'          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ["timers"], match=attrib) -        return cfg_dict -    def parse_attrib_list(self, conf, attrib, param): -        """ -        This function forms the regex to fetch the listed attributes -        from config -        :param conf: configuration data -        :param attrib: attribute name -        :param param: parameter data -        :return: generated rule list configuration -        """ -        r_lst = [] -        if attrib == "area": -            items = findall(r"^" + attrib + " (?:\'*)(\S+)(?:\'*)", conf, M) -        else: -            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': -                    obj = self.parse_area(cfg, item) -                elif attrib == 'virtual-link': -                    obj = self.parse_vlink(cfg) -                else: -                    obj = self.parse_attrib(cfg, attrib) -                obj[param] = item.strip("'") -                if obj: -                    a_lst.append(obj) -            r_lst = sorted(a_lst, key=lambda i: i[param]) -        return r_lst +        cfg_dict = self.parse_attr(conf, ['timers'], match=attrib) +        return cfg_dict      def parse_leaf_list(self, conf, attrib):          """ @@ -167,8 +146,9 @@ class Ospfv2Facts(object):          :param attrib: attribute name          :return: generated rule list configuration          """ +          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("'")) @@ -181,8 +161,9 @@ class Ospfv2Facts(object):          :param attrib: attribute name          :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): @@ -192,18 +173,19 @@ class Ospfv2Facts(object):          :param attrib: 'ospf'          :return: generated config dictionary          """ +          cfg_dict = self.parse_attrib(conf, 'ospf', match=attrib)          return cfg_dict -    def parse_max_metric(self, conf, attrib=None): +    def parse_max_metric(self, conf):          """          This function triggers the parsing of 'max_metric' attributes          :param conf: configuration -        :param attrib: attribute name          :return: generated config dictionary          """ +          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): @@ -213,18 +195,20 @@ class Ospfv2Facts(object):          :param attrib: attribute name          :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, attrib=None): +    def parse_def_info(self, conf):          """          This function triggers the parsing of 'default_information' attributes          :param conf: configuration -        :param attrib: attribute name          :return: generated config dictionary          """ +          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): @@ -234,16 +218,28 @@ class Ospfv2Facts(object):          :param area_id: area identity          :return: generated rule configuration dictionary.          """ -        rule = self.parse_attrib(conf, "area", 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 +    def parse_key(self, conf, key_id): +        """ +        This function triggers the parsing of 'area' attributes. +        :param conf: configuration data +        :param area_id: area identity +        :return: generated rule configuration dictionary. +        """ + +        rule = self.parse_attrib(conf, 'key_id', match=key_id) +        return rule +      def parse_area_type(self, conf, attrib=None):          """          This function triggers the parsing of 'area_type' attributes @@ -251,9 +247,10 @@ class Ospfv2Facts(object):          :param attrib: 'area-type'          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ["normal"], match=attrib) -        cfg_dict["nssa"] = self.parse_attrib(conf, "nssa") -        cfg_dict["stub"] = self.parse_attrib(conf, "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): @@ -262,24 +259,27 @@ class Ospfv2Facts(object):          :param conf: configuration data          :return: generated rule list configuration          """ +          a_lst = []          applications = findall(r"network (.+)", conf, M)          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):          """ -        This function triggers the parsing of 'vitual_link' attributes +        This function triggers the parsing of 'virtual_link' attributes          :param conf: configuration data          :return: generated rule configuration dictionary          """ +          rule = self.parse_attrib(conf, 'vlink') -        r_sub = {"authentication": self.parse_authentication(conf, "authentication")} +        r_sub = {'authentication': self.parse_authentication(conf, +                 'authentication')}          rule.update(r_sub)          return rule @@ -290,19 +290,49 @@ class Ospfv2Facts(object):          :param attrib: 'authentication'          :return: generated config dictionary          """ -        cfg_dict = self.parse_attr(conf, ["plaintext_password"], match=attrib) -        cfg_dict["md5"] = self.parse_md5(conf, "md5") + +        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_md5(self, conf, attrib=None): +    def parse_attrib_list(self, conf, attrib, param):          """ -        This function triggers the parsing of 'md5' attributes -        :param conf: configuration -        :param attrib: 'md5' -        :return: generated config dictionary +        This function forms the regex to fetch the listed attributes +        from config +        :param conf: configuration data +        :param attrib: attribute name +        :param param: parameter data +        :return: generated rule list configuration          """ -        cfg_dict = self.parse_attr(conf, ["key_id"], match=attrib) -        return cfg_dict + +        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) +        else: +            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': +                    obj = self.parse_area(cfg, item) +                elif attrib == 'virtual-link': +                    obj = self.parse_vlink(cfg) +                elif attrib == 'key-id': +                    obj = self.parse_key(cfg, item) +                else: +                    obj = self.parse_attrib(cfg, attrib) +                obj[param] = item.strip("'") +                if obj: +                    a_lst.append(obj) +            r_lst = sorted(a_lst, key=lambda i: i[param]) +        return r_lst      def parse_attrib(self, conf, param, match=None):          """ @@ -310,21 +340,28 @@ class Ospfv2Facts(object):          :param conf: configuration data          :return: generated configuration dictionary          """ +          param_lst = { -            'stub': ["default_cost", "no_summary"], -            'area':  ["shortcut", "authentication"], -            'mpls_te': ["enabled", "router_address"], -            'neighbor': ["priority", "poll_interval"], -            'ospf': ["external", "inter_area", "intra_area"], -            'nssa': ["translate", "default_cost", "no_summary"], -            'redistribute': ["metric", "metric_type", "route_map"], -            'spf': ["delay", "max_holdtime", "initial_holdtime"], -            'range': ["cost", "substitute", "not_advertise"], -            'originate': ["always", "metric", "metric_type", "route_map"], -            'router_lsa': ["administrative", "on_shutdown", "on_startup"], -            'config_routes': ["default_metric", "log_adjacency_changes"], -            '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 @@ -339,16 +376,21 @@ class Ospfv2Facts(object):          :param match: parent node/attribute name.          :return: generated config dictionary.          """ +          config = {}          for attrib in attr_list:              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: +                            config[attrib] = True                          en = conf.find(match + " 'enable'")                      if out >= 1:                          if dis >= 1: @@ -358,7 +400,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): @@ -373,7 +415,10 @@ class Ospfv2Facts(object):          :param attrib: attribute          :return: regex string          """ -        return 'disable' if attrib == "disabled" else 'enable' if attrib == "enabled" 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):          """ @@ -381,7 +426,17 @@ class Ospfv2Facts(object):          :param attrib: attribute.          :return: True/False          """ -        bool_set = ("always", "normal", "enabled", "opaque_lsa", "not_advertise", "administrative", "rfc1583_compatibility") + +        bool_set = ( +            '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): @@ -390,6 +445,20 @@ class Ospfv2Facts(object):          :param attrib: attribute.          :return: True/false.          """ -        num_set = ("ospf", "delay", "metric", "inter_area", "intra_area", "on_startup", "metric_type", "on_shutdown", -                   "max_holdtime", "default_metric", "initial_holdtime") + +        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', +            )          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 c7dc575..c539beb 100644 --- a/plugins/module_utils/network/vyos/utils/utils.py +++ b/plugins/module_utils/network/vyos/utils/utils.py @@ -7,7 +7,6 @@  from __future__ import absolute_import, division, print_function  __metaclass__ = type -import q  from ansible.module_utils.six import iteritems  from ansible_collections.ansible.netcommon.plugins.module_utils.compat import (      ipaddress, diff --git a/plugins/modules/vyos_ospfv2.py b/plugins/modules/vyos_ospfv2.py index 73528eb..866ed76 100644 --- a/plugins/modules/vyos_ospfv2.py +++ b/plugins/modules/vyos_ospfv2.py @@ -39,21 +39,24 @@ DOCUMENTATION = """  ---  module: vyos_ospfv2  version_added: 2.10 -short_description: Manages attributes of OSPF IPv4 routes on VyOS network devices. -description: This module manages attributes of OSPF IPv4 routes on VyOS network devices. -author: Rohit Thakur (@rohitthakur2590) +short_description: This resource module configures and manages attributes of OSPFv2 routes on VyOS network devices. +description: This resource module configures and manages attributes of OSPFv2 routes on VyOS network devices. +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). +author: +  - Rohit Thakur (@rohitthakur2590)  options:    config: -    description: A provided OSPF route configuration. -    type: list -    elements: dict +    description: A provided OSPFv2 route configuration. +    type: dict      suboptions: -      ospf_area: -        description: OSPF area. +      areas: +        description: OSPFv2 area.          type: list          elements: dict          suboptions: -          area: +          area_id:              description: Configured to discard packets.              type: str            area_type: @@ -61,12 +64,15 @@ options:              type: dict              suboptions:                normal: -                description: Normal OSPF area. +                description: Normal OSPFv2 area.                  type: bool                nssa: -                description: Nssa OSPF area. +                description: Nssa OSPFv2 area.                  type: dict                  suboptions: +                  set:  +                    description: Enabling nssa. +                    type: bool                    default_cost:                      description: Summary-default cost of nssa area.                      type: int @@ -78,9 +84,12 @@ options:                      type: str                      choices: ['always', 'candidate', 'never']                stub:  -                description: Stub OSPF area. +                description: Stub OSPFv2 area.                  type: dict                  suboptions: +                  set:  +                    description: Enabling stub. +                    type: bool                    default_cost:                      description: Summary-default cost of stub area.                      type: int @@ -88,17 +97,17 @@ options:                      description: Do not inject inter-area routes into stub.                      type: bool            authentication: -            description: OSPF area authentication type. +            description: OSPFv2 area authentication type.              type: str              choices: ['plaintext-password', 'md5']            network: -            description: OSPF network. +            description: OSPFv2 network.              type: list              elements: dict              suboptions:                address:                  required: True -                description: OSPF IPv4 network address. +                description: OSPFv2 IPv4 network address.                  type: str             range:              description: Summarize routes matching prefix (border routers only). @@ -130,12 +139,13 @@ options:                  description: virtual link address.                  type: str                authentication: -                description: OSPF area authentication type. +                description: OSPFv2 area authentication type.                  type: dict                  suboptions:                    md5:                      description: MD5 key id based authentication. -                    type: dict +                    type: list +                    elements: dict                      suboptions:                        key_id:                          description: MD5 key id. @@ -163,7 +173,7 @@ options:           type: str           choices: ['detail']        max_metric:  -        description: OSPF maximum/infinite-distance metric. +        description: OSPFv2 maximum/infinite-distance metric.          type: dict          suboptions:            router_lsa: @@ -180,7 +190,7 @@ options:                  description: Time to advertise self as stub-router                  type: int           auto_cost: -        description: Calculate OSPF interface cost according to bandwidth. +        description: Calculate OSPFv2 interface cost according to bandwidth.          type: dict          suboptions:            reference_bandwidth: @@ -198,10 +208,10 @@ options:                  description: Always advertise default route.                  type: bool                metric: -                description: OSPF default metric. +                description: OSPFv2 default metric.                  type: int                metric_type: -                description: OSPF Metric types for default routes. +                description: OSPFv2 Metric types for default routes.                  type: int                route_map:                  description: Route map references. @@ -214,10 +224,10 @@ options:          type: dict          suboptions:            global: -            description: Global OSPF administrative distance. +            description: Global OSPFv2 administrative distance.              type: int            ospf:  -            description: OSPF administrative distance. +            description: OSPFv2 administrative distance.              type: dict              suboptions:                external:  @@ -255,11 +265,11 @@ options:              description: Neighbor priority.              type: int               parameters: -        descriptions: OSPF specific parameters. +        descriptions: OSPFv2 specific parameters.          type: dict          suboptions:            abr_type:  -           description: OSPF ABR Type. +           description: OSPFv2 ABR Type.             type: str             choices: ['cisco', 'ibm', 'shortcut', 'standard']           opaque_lsa: @@ -290,7 +300,7 @@ options:              description: Metric for redistribution routes.              type: int            metric_type: -            description: OSPF Metric types. +            description: OSPFv2 Metric types.              type: int            route_map:              description: Route map references. @@ -315,7 +325,7 @@ options:              type: dict              suboptions:                spf: -                description: OSPF SPF timers. +                description: OSPFv2 SPF timers.                  type: dict                  suboptions:                    delay: @@ -327,6 +337,16 @@ options:                    max_holdtime:                      description: maximum hold time (sec).                      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') +    type: str    state:      description:        - The state the configuration should be left in. @@ -346,35 +366,66 @@ EXAMPLES = """  # Before state:  # -------------  # -# vyos@192# run show configuration commands | grep ospf +# vyos@vyos# run show  configuration commands | grep ospf  +#   # -- name: Merge the provided configuration with the existing running configuration -      vyos_ospf_routes: +- name: Merge the provided configuration with the exisiting running configuration +      vyos.vyos.vyos_ospfv2:          config: -          - afi: 'ipv4' -            ospf_area: -              - area: 0 -                network: 192.168.0.0/24 -            default_information: -              originate: -                always: true -                metric: 2 -                metric_type: 10 -            log_adjacency_changes: "details" -            parameters: -              router_id: 10.1.1.1 -            redistribute: -              - route_type: 'connected' -                metric_type: 2 -                route_map: 'CONNECT' -          - afi: 'ipv6' -            ospf_area: -              - area: 0.0.0.0 -                range: 2001:db8:1::/64 -            parameters: -              router-id 192.168.1.1 -            redistribute: -              - route_type: 'connected' +           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  #  # @@ -385,276 +436,432 @@ EXAMPLES = """  # before": []  #  #    "commands": [ -#       "set interfaces ethernet eth1 firewall in name 'INBOUND'",  -#       "set protocols ospf area 0 network 192.168.0.0/24", +#       "set protocols ospf mpls-te enable", +#       "set protocols ospf mpls-te router-address '192.0.11.11'", +#       "set protocols ospf redistribute bgp", +#       "set protocols ospf redistribute bgp metric-type 2", +#       "set protocols ospf redistribute bgp metric 10", +#       "set protocols ospf default-information originate metric-type 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 log-adjacency-changes", -#       "set protocols ospf parameters router-id 10.1.1.1", -#       "set protocols ospf redistribute connected metric-type 2", -#       "set protocols ospf redistribute connected route-map CONNECT", -#       "set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64, -#       "set protocols ospfv3 parameters router-id 192.168.1.1, -#       "set protocols ospfv3 redistribute connected +#       "set protocols ospf default-information originate route-map ingress", +#       "set protocols ospf auto-cost reference-bandwidth '2'", +#       "set protocols ospf parameters router-id '192.0.1.1'", +#       "set protocols ospf parameters opaque-lsa", +#       "set protocols ospf parameters abr-type 'cisco'", +#       "set protocols ospf parameters rfc1583-compatibility", +#       "set protocols ospf passive-interface eth1", +#       "set protocols ospf passive-interface eth2", +#       "set protocols ospf max-metric router-lsa on-shutdown 10", +#       "set protocols ospf max-metric router-lsa administrative", +#       "set protocols ospf max-metric router-lsa on-startup 10", +#       "set protocols ospf log-adjacency-changes 'detail'", +#       "set protocols ospf neighbor 192.0.11.12 priority 2", +#       "set protocols ospf neighbor 192.0.11.12 poll-interval 10", +#       "set protocols ospf neighbor 192.0.11.12", +#       "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 '3'", +#       "set protocols ospf area 3 area-type nssa", +#       "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 20", +#       "set protocols ospf area '4'", +#       "set protocols ospf area 4 network 192.0.2.0/24"  #    ]  # -# "after": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] +# "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" +#            } +#        ] +#    }  #  # After state:  # -------------  # -# vyos@vyos:~$ show configuration commands| grep firewall -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected +# 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' -# Using replaced +# Using merged  #  # Before state:  # -------------  # -# vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected -# -- name: Replace the provided configuration with the existing running configuration -      vyos_ospf_routes: +# vyos@vyos# run show  configuration commands | grep ospf  +#  +# +- name: Merge the provided configuration to update exisiting running configuration +      vyos.vyos.vyos_ospfv2:          config: -          - afi: 'ipv4' -            ospf_area: -              - area: 0 -                network: 192.168.0.0/24 -                area_type: -                  normal: True -            default_information: -              originate: -                always: true -                metric: 2 -                metric_type: 10 -            log_adjacency_changes: "details" -            parameters: -              router_id: 10.1.1.1 -            redistribute: -              - route_type: 'static' -                metric_type: 2 -                route_map: 'STATIC' -          - afi: 'ipv6' -            ospf_area: -              - area: 0.0.0.0 -                range: 2001:db8:1::/64 -            parameters: -              router-id 192.168.1.1 -            redistribute: -              - route_type: 'connected' -        state: replaced +           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  #  #  # -------------------------  # Module Execution Result  # -------------------------  # -# before": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] +# "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 redistribute connected", -#       "set protocols ospf area 0 area_type normal", -#       "set protocols ospf redistribute static metric-type 2", -#       "set protocols ospf redistribute static route-map CONNECT" +#       "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"  #    ]  # -# "after": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "area_type":  -#                               { -#                                 normal: true -#                               } -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "static",  -#                            "metric_type": 2 -#                            "route_map": "STATIC" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connected", -#                            }  -#                        ] +# "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", +#                }, +#                "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 +#                    }, +#                    { +#                        "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" +#            } +#        ] +#    }  #  # After state:  # -------------  # -# vyos@vyos:~$ show configuration commands| grep firewall -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute static metric-type 2 -# set protocols ospf redistribute static route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:2::/64 -# set protocols ospfv3 parameters router-id 192.168.2.1 -# set protocols ospfv3 redistribute connected +# 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 network '192.0.2.0/24' +# set protocols ospf area 4 network '192.0.22.0/24' +# set protocols ospf area 4 network '192.0.32.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'  # Using replaced @@ -663,47 +870,89 @@ EXAMPLES = """  # -------------  #  # vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected -# -- name: Replace the provided configuration with the existing running configuration -      vyos_ospf_routes: +# 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: Replace ospfv2 routes attributes configuration. +      vyos.vyos.vyos_ospfv2:          config: -          - afi: 'ipv4' -            ospf_area: -              - area: 0 -                network: 192.168.0.0/24 -                area_type: -                  normal: True -            default_information: -              originate: -                always: true -                metric: 2 -                metric_type: 10 -            log_adjacency_changes: "details" -            parameters: -              router_id: 10.1.1.1 -            redistribute: -              - route_type: 'static' -                metric_type: 2 -                route_map: 'STATIC' -          - afi: 'ipv6' -            ospf_area: -              - area: 0.0.0.0 -                range: 2001:db8:1::/64 -            parameters: -              router-id 192.168.1.1 -            redistribute: -              - route_type: 'connected' +           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  #  # @@ -711,608 +960,968 @@ EXAMPLES = """  # Module Execution Result  # -------------------------  # -# before": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] -#                } -#    ] -# -#    "commands": [ -#       "delete protocols ospf redistribute connected", -#       "set protocols ospf area 0 area_type normal", -#       "set protocols ospf redistribute static metric-type 2", -#       "set protocols ospf redistribute static route-map CONNECT" -#    ] -# -# "after": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "area_type":  -#                               { -#                                 normal: true -#                               } -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "static",  -#                            "metric_type": 2 -#                            "route_map": "STATIC" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connected", -#                            }  -#                        ] +#    "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 passive-interface eth2", +#     "delete protocols ospf area 3", +#     "delete protocols ospf area 4 range 192.0.3.0/24 cost", +#     "delete protocols ospf area 4 range 192.0.3.0/24", +#     "delete protocols ospf area 4 range 192.0.4.0/24 cost", +#     "delete protocols ospf area 4 range 192.0.4.0/24", +#     "set protocols ospf mpls-te router-address '192.0.22.22'", +#     "set protocols ospf area 4 range 192.0.42.0/24 cost 10", +#     "set protocols ospf area 4 range 192.0.42.0/24", +#     "set protocols ospf area 4 network 192.0.12.0/24", +#     "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": "192.0.42.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" +#            } +#        ] +#    } +#   # After state:  # -------------  # -# vyos@vyos:~$ show configuration commands| grep firewall -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute static metric-type 2 -# set protocols ospf redistribute static route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:2::/64 -# set protocols ospfv3 parameters router-id 192.168.2.1 -# set protocols ospfv3 redistribute connected +# 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 4 area-type stub default-cost '20' +# set protocols ospf area 4 network '192.0.2.0/24' +# set protocols ospf area 4 network '192.0.12.0/24' +# set protocols ospf area 4 network '192.0.22.0/24' +# set protocols ospf area 4 network '192.0.32.0/24' +# set protocols ospf area 4 range 192.0.42.0/24 cost '10' +# 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.22.22' +# 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 redistribute bgp metric '10' +# set protocols ospf redistribute bgp metric-type '2' -# Using replaced +# Using rendered  # -# Before state: -# -------------  # -# vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected -# -- name: Replace the provided configuration with the existing running configuration -      vyos_ospf_routes: +- name: Render the commands for provided  configuration +      vyos.vyos.vyos_ospfv2:          config: -          - afi: 'ipv4' -            ospf_area: -              - area: 0 -                network: 192.168.0.0/24 -                area_type: -                  normal: True -            default_information: -              originate: -                always: true -                metric: 2 -                metric_type: 10 -            log_adjacency_changes: "details" -            parameters: -              router_id: 10.1.1.1 -            redistribute: -              - route_type: 'static' -                metric_type: 2 -                route_map: 'STATIC' -          - afi: 'ipv6' -            ospf_area: -              - area: 0.0.0.0 -                range: 2001:db8:1::/64 -            parameters: -              router-id 192.168.1.1 -            redistribute: -              - route_type: 'connected' -        state: replaced +           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  #  #  # -------------------------  # Module Execution Result  # -------------------------  # -# before": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] -#                } -#    ]  # -#    "commands": [ -#       "delete protocols ospf redistribute connected", -#       "set protocols ospf area 0 area_type normal", -#       "set protocols ospf redistribute static metric-type 2", -#       "set protocols ospf redistribute static route-map CONNECT" +# "rendered": [ +#        [ +#       "set protocols ospf mpls-te enable", +#       "set protocols ospf mpls-te router-address '192.0.11.11'", +#       "set protocols ospf redistribute bgp", +#       "set protocols ospf redistribute bgp metric-type 2", +#       "set protocols ospf redistribute bgp metric 10", +#       "set protocols ospf default-information originate metric-type 2", +#       "set protocols ospf default-information originate always", +#       "set protocols ospf default-information originate metric 10", +#       "set protocols ospf default-information originate route-map ingress", +#       "set protocols ospf auto-cost reference-bandwidth '2'", +#       "set protocols ospf parameters router-id '192.0.1.1'", +#       "set protocols ospf parameters opaque-lsa", +#       "set protocols ospf parameters abr-type 'cisco'", +#       "set protocols ospf parameters rfc1583-compatibility", +#       "set protocols ospf passive-interface eth1", +#       "set protocols ospf passive-interface eth2", +#       "set protocols ospf max-metric router-lsa on-shutdown 10", +#       "set protocols ospf max-metric router-lsa administrative", +#       "set protocols ospf max-metric router-lsa on-startup 10", +#       "set protocols ospf log-adjacency-changes 'detail'", +#       "set protocols ospf neighbor 192.0.11.12 priority 2", +#       "set protocols ospf neighbor 192.0.11.12 poll-interval 10", +#       "set protocols ospf neighbor 192.0.11.12", +#       "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 '3'", +#       "set protocols ospf area 3 area-type nssa", +#       "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 20", +#       "set protocols ospf area '4'", +#       "set protocols ospf area 4 network 192.0.2.0/24"  #    ] + + +# Using parsed +# +# +- name: Render the commands for provided  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' + 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'" +        state: parsed  # -# "after": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "area_type":  -#                               { -#                                 normal: true -#                               } -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "static",  -#                            "metric_type": 2 -#                            "route_map": "STATIC" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connected", -#                            }  -#                        ] -#                } -#    ]  # -# After state: -# ------------- +# ------------------------- +# Module Execution Result +# ------------------------- +#  # -# vyos@vyos:~$ show configuration commands| grep firewall -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute static metric-type 2 -# set protocols ospf redistribute static route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:2::/64 -# set protocols ospfv3 parameters router-id 192.168.2.1 -# set protocols ospfv3 redistribute connected +# "parsed": { +#        "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" +#            } +#        ] +#    } +# } -# Using replaced +# Using gathered  #  # Before state:  # -------------  #  # vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected -# -- name: Replace the provided configuration with the existing running configuration -      vyos_ospf_routes: -        config: -          - afi: 'ipv4' -            ospf_area: -              - area: 0 -                network: 192.168.0.0/24 -                area_type: -                  normal: True -            default_information: -              originate: -                always: true -                metric: 2 -                metric_type: 10 -            log_adjacency_changes: "details" -            parameters: -              router_id: 10.1.1.1 -            redistribute: -              - route_type: 'static' -                metric_type: 2 -                route_map: 'STATIC' -          - afi: 'ipv6' -            ospf_area: -              - area: 0.0.0.0 -                range: 2001:db8:1::/64 -            parameters: -              router-id 192.168.1.1 -            redistribute: -              - route_type: 'connected' -        state: replaced +# 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: Gather ospfv2 routes config with provided configurations +      vyos.vyos.vyos_ospfv2: +          config: +          state: gathered  #  #  # -------------------------  # Module Execution Result  # -------------------------  # -# before": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] -#                } -#    ] -# -#    "commands": [ -#       "delete protocols ospf redistribute connected", -#       "set protocols ospf area 0 area_type normal", -#       "set protocols ospf redistribute static metric-type 2", -#       "set protocols ospf redistribute static route-map CONNECT" -#    ] -# -# "after": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "area_type":  -#                               { -#                                 normal: true -#                               } -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "static",  -#                            "metric_type": 2 -#                            "route_map": "STATIC" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connected", -#                            }  -#                        ] +#    "gathered": { +#        "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" +#            } +#        ] +#    }  #  # After state:  # -------------  # -# vyos@vyos:~$ show configuration commands| grep firewall -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute static metric-type 2 -# set protocols ospf redistribute static route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:2::/64 -# set protocols ospfv3 parameters router-id 192.168.2.1 -# set protocols ospfv3 redistribute connected +# 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'  # Using deleted  # -# Before state: +# Before state  # -------------  #  # vyos@192# run show configuration commands | grep ospf -# set protocols ospf area 0 network 192.168.0.0/24 -# 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 log-adjacency-changes details -# set protocols ospf parameters router-id 10.1.1.1 -# set protocols ospf redistribute connected metric-type 2 -# set protocols ospf redistribute connected route-map CONNECT -# set protocols ospfv3 area 0.0.0.0 range 2001:db8:1::/64 -# set protocols ospfv3 parameters router-id 192.168.1.1 -# set protocols ospfv3 redistribute connected -# -- name: Delete all the configuration -      vyos_ospf_routes: +# 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 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 Result -# ------------------------- -# -# before": [ -#        { -#                { -#                    "afi": "ipv4", -#                    "ospf_area":[ -#                        { -#                            "area": "0",  -#                            "network": "192.168.0.0/24" -#                        } -#                      ], -#                    "default_information":  -#                        { -#                            "originate":  -#                               { -#                                 always: true, -#                                 metric: 2,  -#                                 metric_type: 10  -#                               } -#                        }, -#                   "log_adjacency_changes": "details" -#                   "parameters": -#                        { -#                            "router_id": "10.1.1.1" -#                        }, -#                    "redistribute":[ -#                        { -#                            "route_type": "connetced",  -#                            "metric_type": 2 -#                            "route_map": "CONNECT" -#                        } -#                      ] -#                },  -#                { -#                    "afi": "ipv6",  -#                    "ospf_area":[ -#                        { -#                            "area": "0.0.0.0",  -#                        } -#                       ], -#                    "range": "2001:db8:1::/64",  -#                    "parameters": -#                        { -#                            "router_id": "192.168.1.1" -#                        }, -#                    "redistribute": -#                        [ -#                            { -#                               "route_type": "connetced", -#                            }  -#                        ] +# ------------------------ +# 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 +#                    }  #                } -#    ] -# -#    "commands": [ -#       "delete protocols ospf", -#       "delete protocols ospfv3", +#            }, +#            { +#                "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  # -# After state: +# Before state  # -------------  # -# vyos@vyos:~$ show configuration commands| grep firewall +# 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 +# +# +# ------------------------ +# 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" +#    ] +# +# "after": [] +# After state +# ------------ +# vyos@192# run show configuration commands | grep ospf  """ @@ -1320,12 +1929,14 @@ RETURN = """  before:    description: The configuration prior to the model invocation.    returned: always +  type: dict    sample: >      The configuration returned will always be in the same format       of the parameters above.  after:    description: The resulting configuration model invocation.    returned: when changed +  type: dict    sample: >      The configuration returned will always be in the same format       of the parameters above. @@ -1333,7 +1944,8 @@ commands:    description: The set of commands pushed to the remote device.    returned: always    type: list -  sample: ['command 1', 'command 2', 'command 3'] +  sample: ['set protocols ospf parameters router-id 192.0.1.1', +           'set protocols ospf passive-interface 'eth1']  """ diff --git a/tests/integration/targets/vyos_ospfv2/defaults/main.yaml b/tests/integration/targets/vyos_ospfv2/defaults/main.yaml new file mode 100644 index 0000000..852a6be --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_ospfv2/meta/main.yaml b/tests/integration/targets/vyos_ospfv2/meta/main.yaml new file mode 100644 index 0000000..7413320 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/meta/main.yaml @@ -0,0 +1,3 @@ +--- +dependencies: +  - prepare_vyos_tests diff --git a/tests/integration/targets/vyos_ospfv2/tasks/cli.yaml b/tests/integration/targets/vyos_ospfv2/tasks/cli.yaml new file mode 100644 index 0000000..93eb2fe --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases +  find: +    paths: '{{ role_path }}/tests/cli' +    patterns: '{{ testcase }}.yaml' +    use_regex: true +  register: test_cases +  delegate_to: localhost + +- name: Set test_items +  set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) +  include: '{{ test_case_to_run }}' +  vars: +    ansible_connection: ansible.netcommon.network_cli +  with_items: '{{ test_items }}' +  loop_control: +    loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_ospfv2/tasks/main.yaml b/tests/integration/targets/vyos_ospfv2/tasks/main.yaml new file mode 100644 index 0000000..a3db933 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml +  tags: +    - cli diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_ospfv2/tests/cli/_parsed_config.cfg new file mode 100644 index 0000000..9cc720b --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/_parsed_config.cfg @@ -0,0 +1,29 @@ +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' diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/_populate.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/_populate.yaml new file mode 100644 index 0000000..9f358d5 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/_populate.yaml @@ -0,0 +1,35 @@ +--- +- name: Setup +  vars: +    lines: "set protocols ospf mpls-te 'enable' \n +            set protocols ospf mpls-te router-address '192.0.11.11' \n +            set protocols ospf redistribute bgp metric-type '2' \n +            set protocols ospf redistribute bgp metric '10'\n +            set protocols ospf default-information originate metric-type '2' \n +            set protocols ospf default-information originate 'always' \n +            set protocols ospf default-information originate metric '10' \n +            set protocols ospf default-information originate route-map 'ingress' \n +            set protocols ospf auto-cost reference-bandwidth '2' \n +            set protocols ospf parameters router-id '192.0.1.1' \n +            set protocols ospf parameters 'opaque-lsa' \n +            set protocols ospf parameters abr-type 'cisco' \n +            set protocols ospf parameters 'rfc1583-compatibility' \n +            set protocols ospf passive-interface 'eth1' \n +            set protocols ospf passive-interface 'eth2' \n +            set protocols ospf max-metric router-lsa on-shutdown '10' \n +            set protocols ospf max-metric router-lsa 'administrative' \n +            set protocols ospf max-metric router-lsa on-startup '10' \n +            set protocols ospf log-adjacency-changes 'detail' \n +            set protocols ospf neighbor 192.0.11.12 priority '2' \n +            set protocols ospf neighbor 192.0.11.12 poll-interval '10' \n +            set protocols ospf area 2 authentication 'plaintext-password' \n +            set protocols ospf area 2 shortcut 'enable' \n +            set protocols ospf area 2 area-type 'normal' \n +            set protocols ospf area 3 area-type 'nssa' \n +            set protocols ospf area 4 range 192.0.3.0/24 cost '10' \n +            set protocols ospf area 4 range 192.0.4.0/24 cost '12' \n +            set protocols ospf area 4 area-type stub default-cost '20' \n +            set protocols ospf area 4 network '192.0.2.0/24'" + +  ansible.netcommon.cli_config: +    config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/_remove_config.yaml new file mode 100644 index 0000000..7360870 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/_remove_config.yaml @@ -0,0 +1,6 @@ +--- +- name: Remove Config +  vars: +    lines: "delete protocols ospf\n" +  ansible.netcommon.cli_config: +    config: '{{ lines }}' diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml new file mode 100644 index 0000000..150242a --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/delete_single.yaml @@ -0,0 +1,57 @@ +--- +- 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/deleted.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/deleted.yaml new file mode 100644 index 0000000..a61f5a7 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/deleted.yaml @@ -0,0 +1,48 @@ +--- +- 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: +        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['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that the after dicts were correctly generated +      assert: +        that: +          - "{{ deleted['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['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/empty_config.yaml new file mode 100644 index 0000000..4566bf4 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/empty_config.yaml @@ -0,0 +1,49 @@ +--- +- debug: +    msg: START vyos_ospfv2 empty_config integration tests on connection={{ +      ansible_connection }} + +- name: Merged with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv2: +    config: +    state: merged + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv2: +    config: +    state: replaced + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Parsed with empty running_config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv2: +    running_config: +    state: parsed + +- assert: +    that: +      - result.msg == 'value of running_config parameter must not be empty for state +        parsed' + +- name: Rendered with empty config should give appropriate error message +  register: result +  ignore_errors: true +  vyos.vyos.vyos_ospfv2: +    config: +    state: rendered + +- assert: +    that: +      - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml new file mode 100644 index 0000000..22c378b --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/gathered.yaml @@ -0,0 +1,33 @@ +--- +- debug: +    msg: START vyos_ospfv2 gathered integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Merge the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv2: &id001 +        config: +        state: gathered + +    - name: Assert that gathered dicts was correctly generated +      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.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/merged.yaml new file mode 100644 index 0000000..6a58bb5 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/merged.yaml @@ -0,0 +1,101 @@ +--- +- debug: +    msg: START vyos_ospfv2 merged integration tests on connection={{ ansible_connection +      }} + +- include_tasks: _remove_config.yaml + +- block: + +    - name: Merge the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv2: &id001 +        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 + +    - name: Assert that before dicts were correctly generated +      assert: +        that: "{{ merged['before'] == result['before'] }}" + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ merged['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that after dicts was correctly generated +      assert: +        that: +          - "{{ merged['after'] == result['after'] }}" + +    - name: Merge the provided configuration with 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 + +    - name: Assert that before dicts were correctly generated +      assert: +        that: +          - "{{ merged['after'] == result['before'] }}" +  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 new file mode 100644 index 0000000..453dbb0 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/merged_update.yaml @@ -0,0 +1,70 @@ +--- +- debug: +    msg: START vyos_ospfv2 merged integration tests on connection={{ ansible_connection +      }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Merge the provided configuration with the exisiting running configuration +      register: result +      vyos.vyos.vyos_ospfv2: &id001 +        config: +          log_adjacency_changes: 'detail' +          max_metric: +            router_lsa: +              administrative: true +              on_shutdown: 10 +              on_startup: 10 +          passive_interface: +            - 'eth1' +          areas: +            - area_id: '3' +              area_type: +                nssa: +                  set: true +            - area_id: '4' +              area_type: +                stub: +                  set: false +              network: +                - address: '192.0.2.0/24' +                - address: '192.0.22.0/24' +                - address: '192.0.32.0/24' +        state: merged + +    - name: Assert that before dicts were correctly generated +      assert: +        that: "{{ merged_update['before'] == result['before'] }}" + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ merged_update['commands'] | symmetric_difference(result['commands']) |length\ +            \ == 0 }}" + +    - name: Assert that after dicts was correctly generated +      assert: +        that: +          - "{{ merged_update['after'] == result['after'] }}" + +    - name: Merge the provided configuration with 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 + +    - name: Assert that before dicts were correctly generated +      assert: +        that: +          - "{{ merged_update['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml
\ No newline at end of file diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml new file mode 100644 index 0000000..6fbe2f9 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/parsed.yaml @@ -0,0 +1,41 @@ +--- +- debug: +    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 diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml new file mode 100644 index 0000000..86c07cf --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/rendered.yaml @@ -0,0 +1,88 @@ +--- +- debug: +    msg: START vyos_ospfv2 rendered integration tests on connection={{ +      ansible_connection }} + +- 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 +        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 + +    - name: Assert that correct set of commands were generated +      assert: +        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 diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/replaced.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/replaced.yaml new file mode 100644 index 0000000..07606f9 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/replaced.yaml @@ -0,0 +1,100 @@ +--- +- debug: +    msg: START vyos_ospfv2 replaced integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + +    - name: Replace device configurations of listed ospfv2 routes with provided configurations +      register: result +      vyos.vyos.vyos_ospfv2: &id001 +        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: '1.1.2.0/24' +                  cost: 10 +        state: replaced + +    - name: Assert that correct set of commands were generated +      assert: +        that: +          - "{{ replaced['commands'] | symmetric_difference(result['commands'])\ +            \ |length == 0 }}" + +    - name: Assert that before dicts are correctly generated +      assert: +        that: +          - "{{ populate == result['before'] }}" + +    - name: Assert that after dict is correctly generated +      assert: +        that: +          - "{{ replaced['after'] == result['after'] }}" + +    - name: Replace device configurations of listed ospfv2 routes  with provided configurarions +        (IDEMPOTENT) +      register: result +      vyos.vyos.vyos_ospfv2: *id001 + +    - name: Assert that task was idempotent +      assert: +        that: +          - result['changed'] == false + +    - name: Assert that before dict is correctly generated +      assert: +        that: +          - "{{ replaced['after'] == result['before'] }}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/tests/cli/rtt.yaml b/tests/integration/targets/vyos_ospfv2/tests/cli/rtt.yaml new file mode 100644 index 0000000..7efc2a7 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/tests/cli/rtt.yaml @@ -0,0 +1,149 @@ +--- +- debug: +    msg: START vyos_ospfv2 round trip integration tests on connection={{ +      ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + +    - name: Apply the provided configuration (base config) +      register: base_config +      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 + +    - name: Gather ospfv2 facts +      vyos.vyos.vyos_facts: +        gather_subset: +          - default +        gather_network_resources: +          - ospfv2 + +    - name: Apply the provided configuration (config to be reverted) +      register: result +      vyos.vyos.vyos_ospfv2: +        config: +          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' +        state: replaced + +    - name: Assert that changes were applied +      assert: +        that: "{{ round_trip['after'] == result['after'] }}" + +    - name: Revert back to base config using facts round trip +      register: revert +      vyos.vyos.vyos_ospfv2: +        config: "{{ ansible_facts['network_resources']['ospfv2'] }}" +        state: replaced + +    - name: Assert that config was reverted +      assert: +        that: "{{ base_config['after'] == revert['after']}}" +  always: + +    - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_ospfv2/vars/main.yaml b/tests/integration/targets/vyos_ospfv2/vars/main.yaml new file mode 100644 index 0000000..76a54e3 --- /dev/null +++ b/tests/integration/targets/vyos_ospfv2/vars/main.yaml @@ -0,0 +1,444 @@ +--- +merged: +  before: [] +  commands: +    - set protocols ospf mpls-te enable +    - set protocols ospf mpls-te router-address '192.0.11.11' +    - set protocols ospf redistribute bgp +    - set protocols ospf redistribute bgp metric-type 2 +    - set protocols ospf redistribute bgp metric 10 +    - set protocols ospf default-information originate metric-type 2 +    - set protocols ospf default-information originate always +    - set protocols ospf default-information originate metric 10 +    - set protocols ospf default-information originate route-map ingress +    - set protocols ospf auto-cost reference-bandwidth '2' +    - set protocols ospf parameters router-id '192.0.1.1' +    - set protocols ospf parameters opaque-lsa +    - set protocols ospf parameters abr-type 'cisco' +    - set protocols ospf parameters rfc1583-compatibility +    - set protocols ospf passive-interface eth1 +    - set protocols ospf passive-interface eth2 +    - set protocols ospf max-metric router-lsa on-shutdown 10 +    - set protocols ospf max-metric router-lsa administrative +    - set protocols ospf max-metric router-lsa on-startup 10 +    - set protocols ospf log-adjacency-changes 'detail' +    - set protocols ospf neighbor 192.0.11.12 priority 2 +    - set protocols ospf neighbor 192.0.11.12 poll-interval 10 +    - set protocols ospf neighbor 192.0.11.12 +    - 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 '3' +    - set protocols ospf area 3 area-type nssa +    - 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 20 +    - 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: +          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' +  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' +        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 +          - 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 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: +      - 'eth2' +      - 'eth1' +    redistribute: +      - metric: 10 +        metric_type: 2 +        route_type: 'bgp' +replaced: +  commands: +    - delete protocols ospf passive-interface eth2 +    - delete protocols ospf area 3 +    - delete protocols ospf area 4 range 192.0.3.0/24 cost +    - delete protocols ospf area 4 range 192.0.3.0/24 +    - delete protocols ospf area 4 range 192.0.4.0/24 cost +    - delete protocols ospf area 4 range 192.0.4.0/24 +    - set protocols ospf mpls-te router-address '192.0.22.22' +    - set protocols ospf area 4 range 1.1.2.0/24 cost 10 +    - set protocols ospf area 4 range 1.1.2.0/24 +    - set protocols ospf area 4 network 192.0.12.0/24 +    - 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' +rendered: +  commands: +    - set protocols ospf mpls-te enable +    - set protocols ospf mpls-te router-address '192.0.11.11' +    - set protocols ospf redistribute bgp +    - set protocols ospf redistribute bgp metric-type 2 +    - set protocols ospf redistribute bgp metric 10 +    - set protocols ospf default-information originate metric-type 2 +    - set protocols ospf default-information originate always +    - set protocols ospf default-information originate metric 10 +    - set protocols ospf default-information originate route-map ingress +    - set protocols ospf auto-cost reference-bandwidth '2' +    - set protocols ospf parameters router-id '192.0.1.1' +    - set protocols ospf parameters opaque-lsa +    - set protocols ospf parameters abr-type 'cisco' +    - set protocols ospf parameters rfc1583-compatibility +    - set protocols ospf passive-interface eth1 +    - set protocols ospf passive-interface eth2 +    - set protocols ospf max-metric router-lsa on-shutdown 10 +    - set protocols ospf max-metric router-lsa administrative +    - set protocols ospf max-metric router-lsa on-startup 10 +    - set protocols ospf log-adjacency-changes 'detail' +    - set protocols ospf neighbor 192.0.11.12 priority 2 +    - set protocols ospf neighbor 192.0.11.12 poll-interval 10 +    - set protocols ospf neighbor 192.0.11.12 +    - 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 '3' +    - set protocols ospf area 3 area-type nssa +    - 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 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: [] +deleted: +  commands: +    - 'delete protocols ospf' +  after: [] +round_trip: +  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' diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ospfv2_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv2_config.cfg new file mode 100644 index 0000000..297671b --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv2_config.cfg @@ -0,0 +1,9 @@ +set protocols ospf area 12 area-type normal +set protocols ospf area 12 authentication plaintext-password +set protocols ospf area 12 shortcut enable +set protocols ospf area 14 range 192.0.13.0/24 cost 10 +set protocols ospf area 14 range 192.0.13.0/24 +set protocols ospf area 14 range 192.0.14.0/24 cost 12 +set protocols ospf area 14 range 192.0.14.0/24 +set protocols ospf area 14 area-type stub default-cost 20 +set protocols ospf area 14 network 192.0.12.0/24 diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv2.py b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py new file mode 100644 index 0000000..8e6b095 --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_ospfv2.py @@ -0,0 +1,526 @@ +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible.  If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch +from ansible_collections.vyos.vyos.plugins.modules import vyos_ospfv2 +from ansible_collections.vyos.vyos.tests.unit.modules.utils import ( +    set_module_args, +) +from .vyos_module import TestVyosModule, load_fixture + + +class TestVyosFirewallRulesModule(TestVyosModule): + +    module = vyos_ospfv2 + +    def setUp(self): +        super(TestVyosFirewallRulesModule, self).setUp() +        self.mock_get_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config" +        ) +        self.get_config = self.mock_get_config.start() + +        self.mock_load_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config" +        ) +        self.load_config = self.mock_load_config.start() + +        self.mock_get_resource_connection_config = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection" +        ) +        self.get_resource_connection_config = ( +            self.mock_get_resource_connection_config.start() +        ) + +        self.mock_get_resource_connection_facts = patch( +            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection" +        ) +        self.get_resource_connection_facts = ( +            self.mock_get_resource_connection_facts.start() +        ) + +        self.mock_execute_show_command = patch( +            "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv2.ospfv2.Ospfv2Facts.get_device_data" +        ) + +        self.execute_show_command = self.mock_execute_show_command.start() + +    def tearDown(self): +        super(TestVyosFirewallRulesModule, self).tearDown() +        self.mock_get_resource_connection_config.stop() +        self.mock_get_resource_connection_facts.stop() +        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" + +        def load_from_file(*args, **kwargs): +            output = load_fixture(filename) +            return output + +        self.execute_show_command.side_effect = load_from_file + +    def test_vyos_ospfv2_merged_new_config(self): +        set_module_args( +            dict( +                config=dict( +                    log_adjacency_changes="detail", +                    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', +                        ), +                        dict( +                            area_id="4", +                            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) +                            ] +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        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" +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv2_merged_idem(self): +        set_module_args( +            dict( +                config=dict( +                    areas=[ +                        dict( +                            area_id="12", +                            area_type=dict(normal=True), +                            authentication="plaintext-password", +                            shortcut='enable', +                        ), +                        dict( +                            area_id="14", +                            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) +                            ] +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        self.execute_module(changed=False, commands=[]) + +    def test_vyos_ospfv2_merged_update_existing(self): +        set_module_args( +            dict( +                config=dict( +                    areas=[ +                        dict( +                            area_id="12", +                            area_type=dict(normal=True), +                            authentication="plaintext-password", +                            shortcut='enable', +                        ), +                        dict( +                            area_id="14", +                            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) +                            ] +                        ), +                    ], +                ), +                state="merged", +            ) +        ) +        commands = [ +            "delete protocols ospf area 14 area-type stub", +            "set protocols ospf area 14 network 192.0.22.0/24" +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv2_replaced(self): +        set_module_args( +            dict( +                config=dict( +                    log_adjacency_changes="detail", +                    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', +                        ), +                        dict( +                            area_id="15", +                            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) +                            ] +                        ), +                    ], +                ), +                state="replaced", +            ) +        ) +        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'", +            "delete protocols ospf area 14", +            "set protocols ospf area 15 range 192.0.13.0/24 cost 10", +            "set protocols ospf area 15 range 192.0.13.0/24", +            "set protocols ospf area 15 range 192.0.14.0/24 cost 12", +            "set protocols ospf area 15 range 192.0.14.0/24", +            "set protocols ospf area 15 range 192.0.15.0/24 cost 14", +            "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" +        ] +        self.execute_module(changed=True, commands=commands) + +    def test_vyos_ospfv2_replaced_idem(self): +        set_module_args( +            dict( +                config=dict( +                    areas=[ +                        dict( +                            area_id="12", +                            area_type=dict(normal=True), +                            authentication="plaintext-password", +                            shortcut='enable', +                        ), +                        dict( +                            area_id="14", +                            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) +                            ] +                        ), +                    ], +                ), +                state="replaced", +            ) +        ) +        self.execute_module(changed=False, commands=[]) + +    def test_vyos_ospfv2_deleted_no_config(self): +        set_module_args(dict(config=None, state="deleted")) +        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 +                          } +                      ] +                  } +              ], +          } +        self.assertEqual(sorted(gather_dict), sorted(result["gathered"])) + +    def test_vyos_ospfv2_parsed(self): +        parsed_str = """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 default-information originate 'always' +        set protocols ospf default-information originate metric '10' +        set protocols ospf default-information originate metric-type '2' +set protocols ospf auto-cost reference-bandwidth '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'""" +        set_module_args(dict(running_config=parsed_str, state="parsed")) +        result = self.execute_module(changed=False) +        parsed_list = { +            "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" +                } +            ] +        } +        self.assertEqual(sorted(parsed_list), sorted(result["parsed"])) + +    def test_vyos_ospfv2_rendered(self): +        set_module_args( +            dict( +                config=dict( +                    log_adjacency_changes="detail", +                    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', +                        ), +                        dict( +                            area_id="4", +                            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) +                            ] +                        ), +                    ], +                ), +                state="rendered", +            ) +        ) +        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" +        ] +        result = self.execute_module(changed=False) +        self.assertEqual( +            sorted(result["rendered"]), sorted(commands), result["rendered"] +        ) diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py index 49d4652..e0ab699 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) | 
