diff options
Diffstat (limited to 'ansible_collections/cisco/iosxr/plugins')
254 files changed, 71407 insertions, 0 deletions
diff --git a/ansible_collections/cisco/iosxr/plugins/action/__init__.py b/ansible_collections/cisco/iosxr/plugins/action/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/action/acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/acl_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/acl_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/acls.py b/ansible_collections/cisco/iosxr/plugins/action/acls.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/acls.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/banner.py b/ansible_collections/cisco/iosxr/plugins/action/banner.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/banner.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/bgp.py b/ansible_collections/cisco/iosxr/plugins/action/bgp.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/bgp.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/action/bgp_address_family.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/bgp_address_family.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/bgp_global.py b/ansible_collections/cisco/iosxr/plugins/action/bgp_global.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/bgp_global.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/action/bgp_neighbor_address_family.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/bgp_neighbor_address_family.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/command.py b/ansible_collections/cisco/iosxr/plugins/action/command.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/command.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/config.py b/ansible_collections/cisco/iosxr/plugins/action/config.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/config.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/facts.py b/ansible_collections/cisco/iosxr/plugins/action/facts.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/facts.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/hostname.py b/ansible_collections/cisco/iosxr/plugins/action/hostname.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/hostname.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/interface.py b/ansible_collections/cisco/iosxr/plugins/action/interface.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/interface.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/iosxr.py b/ansible_collections/cisco/iosxr/plugins/action/iosxr.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/iosxr.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/l2_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/l2_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/l2_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/l3_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/l3_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/l3_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/lacp.py b/ansible_collections/cisco/iosxr/plugins/action/lacp.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/lacp.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/lacp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/lacp_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/lacp_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/lag_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/lag_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/lag_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/lldp_global.py b/ansible_collections/cisco/iosxr/plugins/action/lldp_global.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/lldp_global.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/lldp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/lldp_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/lldp_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/logging.py b/ansible_collections/cisco/iosxr/plugins/action/logging.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/logging.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/logging_global.py b/ansible_collections/cisco/iosxr/plugins/action/logging_global.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/logging_global.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/netconf.py b/ansible_collections/cisco/iosxr/plugins/action/netconf.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/netconf.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/ntp_global.py b/ansible_collections/cisco/iosxr/plugins/action/ntp_global.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/ntp_global.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/action/ospf_interfaces.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/ospf_interfaces.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/ospfv2.py b/ansible_collections/cisco/iosxr/plugins/action/ospfv2.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/ospfv2.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/ospfv3.py b/ansible_collections/cisco/iosxr/plugins/action/ospfv3.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/ospfv3.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/action/prefix_lists.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/prefix_lists.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/snmp_server.py b/ansible_collections/cisco/iosxr/plugins/action/snmp_server.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/snmp_server.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/static_routes.py b/ansible_collections/cisco/iosxr/plugins/action/static_routes.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/static_routes.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/system.py b/ansible_collections/cisco/iosxr/plugins/action/system.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/system.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/action/user.py b/ansible_collections/cisco/iosxr/plugins/action/user.py new file mode 100644 index 00000000..d1ba1e15 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/action/user.py @@ -0,0 +1,59 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.utils.display import Display +from ansible_collections.ansible.netcommon.plugins.action.network import ( + ActionModule as ActionNetworkModule, +) + + +display = Display() + + +class ActionModule(ActionNetworkModule): + def run(self, tmp=None, task_vars=None): + del tmp # tmp no longer has any effect + + module_name = self._task.action.split(".")[-1] + self._config_module = True if module_name in ["iosxr_config", "config"] else False + force_cli = module_name in ("iosxr_netconf", "iosxr_config", "iosxr_command", "iosxr_facts") + persistent_connection = self._play_context.connection.split(".")[-1] + warnings = [] + + if (not force_cli and persistent_connection not in ("netconf", "network_cli")) or ( + force_cli and persistent_connection != "network_cli" + ): + return { + "failed": True, + "msg": "Connection type %s is not valid for this module" + % self._play_context.connection, + } + + result = super(ActionModule, self).run(task_vars=task_vars) + if warnings: + if "warnings" in result: + result["warnings"].extend(warnings) + else: + result["warnings"] = warnings + return result diff --git a/ansible_collections/cisco/iosxr/plugins/cliconf/__init__.py b/ansible_collections/cisco/iosxr/plugins/cliconf/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/cliconf/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py b/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py new file mode 100644 index 00000000..706bff6e --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py @@ -0,0 +1,555 @@ +# +# (c) 2017 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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +author: Ansible Networking Team (@ansible-network) +name: iosxr +short_description: Use iosxr cliconf to run command on Cisco IOS XR platform +description: +- This iosxr plugin provides low level abstraction apis for sending and receiving + CLI commands from Cisco IOS XR network devices. +version_added: 1.0.0 +notes: +- IOSXR commit confirmed command varies with IOSXR version releases, + commit_comment and commit_label may or may not + be valid together as per the device version. +options: + commit_confirmed: + type: boolean + default: false + description: + - enable or disable commit confirmed mode + env: + - name: ANSIBLE_IOSXR_COMMIT_CONFIRMED + vars: + - name: ansible_iosxr_commit_confirmed + commit_confirmed_timeout: + type: int + description: + - Commits the configuration on a trial basis for the time specified in seconds or minutes. + env: + - name: ANSIBLE_IOSXR_COMMIT_CONFIRMED_TIMEOUT + vars: + - name: ansible_iosxr_commit_confirmed_timeout + commit_label: + type: str + description: + - Adds label to commit confirmed. + env: + - name: ANSIBLE_IOSXR_COMMIT_LABEL + vars: + - name: ansible_iosxr_commit_label + commit_comment: + type: str + description: + - Adds comment to commit confirmed.. + env: + - name: ANSIBLE_IOSXR_COMMIT_COMMENT + vars: + - name: ansible_iosxr_commit_comment + config_commands: + description: + - Specifies a list of commands that can make configuration changes + to the target device. + - When `ansible_network_single_user_mode` is enabled, if a command sent + to the device is present in this list, the existing cache is invalidated. + version_added: 2.0.0 + type: list + elements: str + default: [] + vars: + - name: ansible_iosxr_config_commands + config_mode_exclusive: + type: boolean + default: false + description: + - enable or disable config mode exclusive + env: + - name: ANSIBLE_IOSXR_CONFIG_MODE_EXCLUSIVE + vars: + - name: ansible_iosxr_config_mode_exclusive +""" + +EXAMPLES = """ +# Use commit confirmed within a task with timeout, label and comment + +- name: Commit confirmed with a task + vars: + ansible_iosxr_commit_confirmed: True + ansible_iosxr_commit_confirmed_timeout: 50 + ansible_iosxr_commit_label: TestLabel + ansible_iosxr_commit_comment: I am a test comment + cisco.iosxr.iosxr_logging_global: + state: merged + config: + buffered: + severity: errors #alerts #informational + correlator: + buffer_size: 2024 + +# Commands (cliconf specific) +# ["commit confirmed 50 label TestLabel comment I am a test comment"] + +# Use commit within a task with label + +- name: Commit label with a task + vars: + ansible_iosxr_commit_label: lblTest + cisco.iosxr.iosxr_hostname: + state: merged + config: + hostname: R1 + +# Commands (cliconf specific) +# ["commit label lblt1"] + +# Use commit confirm with timeout and confirm the commit + +# NOTE - IOSXR waits for a `commit` when the command +# executed is `commit confirmed <timeout>` within the timeout +# period for the config to commit successfully, else a rollback +# happens. + +- name: Example commit confirmed + vars: + ansible_iosxr_commit_confirmed: True + ansible_iosxr_commit_confirmed_timeout: 60 + tasks: + - name: "Commit confirmed with timeout" + cisco.iosxr.iosxr_hostname: + state: merged + config: + hostname: R1 + + - name: "Confirm the Commit" + cisco.iosxr.iosxr_command: + commands: + - commit + +# Commands (cliconf specific) +# ["commit confirmed 60"] + +# Use exclusive mode with a task + +- name: Configure exclusive mode with a task + vars: + ansible_iosxr_config_mode_exclusive: True + cisco.iosxr.iosxr_interfaces: + state: merged + config: + - name: GigabitEthernet0/0/0/2 + description: Configured via Ansible + - name: GigabitEthernet0/0/0/3 + description: Configured via Ansible + +# Commands (cliconf specific) +# ["configure exclusive"] + +# Use Replace option with commit confirmed + +# NOTE - IOSXR waits for a `commit` when the command +# executed is `commit replace confirmed <timeout>` within the timeout +# period for the config to commit successfully, else a rollback +# happens. +# This option is supported by only iosxr_config module + +- name: Example replace config with commit confirmed + vars: + ansible_iosxr_commit_confirmed: True + ansible_iosxr_commit_confirmed_timeout: 60 + tasks: + - name: "Replace config with Commit confirmed" + cisco.iosxr.iosxr_config: + src: 'replace_running_cfg_iosxr.txt' + replace: config + + - name: "Confirm the Commit" + cisco.iosxr.iosxr_command: + commands: + - commit +""" + +import json +import re + +from ansible.errors import AnsibleConnectionFailure +from ansible.module_utils._text import to_text +from ansible.module_utils.common._collections_compat import Mapping +from ansible.module_utils.connection import ConnectionError +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list +from ansible_collections.ansible.netcommon.plugins.plugin_utils.cliconf_base import CliconfBase + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + mask_config_blocks_from_diff, + sanitize_config, +) + + +class Cliconf(CliconfBase): + def __init__(self, *args, **kwargs): + self._device_info = {} + super(Cliconf, self).__init__(*args, **kwargs) + + def get_command_output(self, command): + reply = self.get(command) + data = to_text(reply, errors="surrogate_or_strict").strip() + return data + + def get_device_info(self): + if not self._device_info: + device_info = dict() + device_info["network_os"] = "iosxr" + data = self.get_command_output("show version | utility head -n 20") + match = re.search(r"Version (\S+)$", data, re.M) + if match: + device_info["network_os_version"] = match.group(1) + else: + match = re.search(r"Version (\S+ \S+)$", data, re.M) + if match: + device_info["network_os_version"] = match.group(1) + + match = re.search(r'image file is "(.+)"', data) + if match: + device_info["network_os_image"] = match.group(1) + + model_search_strs = [ + r"^[Cc]isco (.+) \(\) processor", + r"^[Cc]isco ([A-Z0-9\-]+) processor", + r"^[Cc]isco (.+) \(revision", + r"^[Cc]isco (\S+ \S+).+bytes of .*memory", + ] + for item in model_search_strs: + match = re.search(item, data, re.M) + if match: + device_info["network_os_model"] = match.group(1) + break + + hostname = self.get_command_output("show running-config hostname") + match = re.search(r"hostname\s(\S+)$", hostname, re.M) + if match: + device_info["network_os_hostname"] = match.group(1) + + self._device_info = device_info + + return self._device_info + + def configure(self, admin=False, exclusive=False): + prompt = to_text(self._connection.get_prompt(), errors="surrogate_or_strict").strip() + if not prompt.endswith(")#"): + if admin and "admin-" not in prompt: + self.send_command("admin") + if exclusive or self.get_option("config_mode_exclusive"): + self.send_command("configure exclusive") + return + self.send_command("configure terminal") + + def abort(self, admin=False): + prompt = to_text(self._connection.get_prompt(), errors="surrogate_or_strict").strip() + if prompt.endswith(")#"): + self.send_command("abort") + if admin and "admin-" in prompt: + self.send_command("exit") + + def get_config(self, source="running", format="text", flags=None): + if source not in ["running"]: + raise ValueError("fetching configuration from %s is not supported" % source) + + lookup = {"running": "running-config"} + + cmd = "show {0} ".format(lookup[source]) + cmd += " ".join(to_list(flags)) + cmd = cmd.strip() + + return self.send_command(cmd) + + def edit_config( + self, + candidate=None, + commit=True, + admin=False, + exclusive=False, + replace=None, + comment=None, + label=None, + ): + operations = self.get_device_operations() + self.check_edit_config_capability(operations, candidate, commit, replace, comment) + + resp = {} + results = [] + requests = [] + + self.configure(admin=admin, exclusive=exclusive) + + if replace: + candidate = "load {0}".format(replace) + + for line in to_list(candidate): + if not isinstance(line, Mapping): + line = {"command": line} + cmd = line["command"] + results.append(self.send_command(**line)) + requests.append(cmd) + + # Before any commit happened, we can get a real configuration + # diff from the device and make it available by the iosxr_config module. + # This information can be useful either in check mode or normal mode. + resp["show_commit_config_diff"] = self.get("show commit changes diff") + + if commit: + try: + self.commit(comment=comment, label=label, replace=replace) + except AnsibleConnectionFailure as exc: + error_msg = to_text(exc, errors="surrogate_or_strict").strip() + if "Invalid input detected" in error_msg and "comment" in error_msg: + msg = ( + "value of comment option '%s' is ignored as it in not supported by IOSXR" + % comment + ) + self._connection.queue_message("warning", msg) + comment = None + self.commit(comment=comment, label=label, replace=replace) + else: + raise ConnectionError(error_msg) + + else: + self.discard_changes() + + if not self.get_option("commit_confirmed"): + self.abort(admin=admin) + + resp["request"] = requests + resp["response"] = results + return resp + + def get_diff( + self, + candidate=None, + running=None, + diff_match="line", + diff_ignore_lines=None, + path=None, + diff_replace="line", + ): + diff = {} + device_operations = self.get_device_operations() + option_values = self.get_option_values() + + if candidate is None and device_operations["supports_generate_diff"]: + raise ValueError("candidate configuration is required to generate diff") + + if diff_match not in option_values["diff_match"]: + raise ValueError( + "'match' value %s in invalid, valid values are %s" + % (diff_match, ", ".join(option_values["diff_match"])), + ) + + if diff_replace not in option_values["diff_replace"]: + raise ValueError( + "'replace' value %s in invalid, valid values are %s" + % (diff_replace, ", ".join(option_values["diff_replace"])), + ) + + # prepare candidate configuration + sanitized_candidate = sanitize_config(candidate) + candidate_obj = NetworkConfig(indent=1, comment_tokens=["!"]) + candidate_obj.load(sanitized_candidate) + + if running and diff_match != "none": + # running configuration + running = mask_config_blocks_from_diff(running, candidate, "ansible") + running = sanitize_config(running) + + running_obj = NetworkConfig( + indent=1, + contents=running, + ignore_lines=diff_ignore_lines, + comment_tokens=["!"], + ) + configdiffobjs = candidate_obj.difference( + running_obj, + path=path, + match=diff_match, + replace=diff_replace, + ) + + else: + configdiffobjs = candidate_obj.items + + diff["config_diff"] = dumps(configdiffobjs, "commands") if configdiffobjs else "" + return diff + + def get( + self, + command=None, + prompt=None, + answer=None, + sendonly=False, + newline=True, + output=None, + check_all=False, + ): + if output: + raise ValueError("'output' value %s is not supported for get" % output) + return self.send_command( + command=command, + prompt=prompt, + answer=answer, + sendonly=sendonly, + newline=newline, + check_all=check_all, + ) + + def commit(self, comment=None, label=None, replace=None): + """Implements commit functionality of config module + and commit confirmed functionality of cliconf module + + Args: + comment (str, optional): commit comment. Defaults to None. + label (str, optional): commit label. Defaults to None. + replace (bool, optional): Flag to replace commit. Defaults to None. + """ + + cmd_obj = {} + if replace: + cmd_obj["command"] = "commit replace" + if self.get_option("commit_confirmed"): + cmd_obj["command"] = "commit replace confirmed" + if self.get_option("commit_confirmed_timeout"): + cmd_obj["command"] += " {0}".format(self.get_option("commit_confirmed_timeout")) + + cmd_obj[ + "prompt" + ] = "This commit will replace or remove the entire running configuration" + cmd_obj["answer"] = "yes" + + elif self.get_option("commit_confirmed"): + cmd_obj["command"] = "commit confirmed" + if self.get_option("commit_confirmed_timeout"): + cmd_obj["command"] += " {0}".format(self.get_option("commit_confirmed_timeout")) + if self.get_option("commit_label"): + cmd_obj["command"] += " label {0}".format(self.get_option("commit_label")) + if self.get_option("commit_comment"): + cmd_obj["command"] += " comment {0}".format(self.get_option("commit_comment")) + + else: + label = label or self.get_option("commit_label") + comment = comment or self.get_option("commit_comment") + + if comment or label: + cmd_obj["command"] = "commit" + if label: + cmd_obj["command"] += " label {0}".format(label) + if comment: + cmd_obj["command"] += " comment {0}".format(comment) + + else: + cmd_obj["command"] = "commit show-error" + # In some cases even a normal commit, i.e., !replace, + # throws a prompt and we need to handle it before + # proceeding further + cmd_obj["prompt"] = "(C|c)onfirm" + cmd_obj["answer"] = "y" + self.send_command(**cmd_obj) + + def run_commands(self, commands=None, check_rc=True): + if commands is None: + raise ValueError("'commands' value is required") + responses = list() + for cmd in to_list(commands): + if not isinstance(cmd, Mapping): + cmd = {"command": cmd} + + output = cmd.pop("output", None) + if output: + raise ValueError("'output' value %s is not supported for run_commands" % output) + + try: + out = self.send_command(**cmd) + except AnsibleConnectionFailure as e: + if check_rc: + raise + out = getattr(e, "err", e) + + if out is not None: + try: + out = to_text(out, errors="surrogate_or_strict").strip() + except UnicodeError: + raise ConnectionError( + message="Failed to decode output from %s: %s" % (cmd, to_text(out)), + ) + + try: + out = json.loads(out) + except ValueError: + pass + + responses.append(out) + return responses + + def discard_changes(self): + self.send_command("abort") + + def get_device_operations(self): + return { + "supports_diff_replace": True, + "supports_commit": True, + "supports_rollback": False, + "supports_defaults": False, + "supports_onbox_diff": False, + "supports_commit_comment": True, + "supports_multiline_delimiter": False, + "supports_diff_match": True, + "supports_diff_ignore_lines": True, + "supports_generate_diff": True, + "supports_replace": True, + "supports_admin": True, + "supports_commit_label": True, + } + + def get_option_values(self): + return { + "format": ["text"], + "diff_match": ["line", "strict", "exact", "none"], + "diff_replace": ["line", "block", "config"], + "output": [], + } + + def get_capabilities(self): + result = super(Cliconf, self).get_capabilities() + result["rpc"] += ["commit", "discard_changes", "get_diff", "configure", "exit"] + result["device_operations"] = self.get_device_operations() + result.update(self.get_option_values()) + return json.dumps(result) + + def set_cli_prompt_context(self): + """ + Make sure we are in the operational cli mode + :return: None + """ + if self._connection.connected and not self.get_option("commit_confirmed"): + self._update_cli_prompt_context(config_context=")#", exit_command="abort") diff --git a/ansible_collections/cisco/iosxr/plugins/doc_fragments/__init__.py b/ansible_collections/cisco/iosxr/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/doc_fragments/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/doc_fragments/iosxr.py b/ansible_collections/cisco/iosxr/plugins/doc_fragments/iosxr.py new file mode 100644 index 00000000..5049db81 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/doc_fragments/iosxr.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +class ModuleDocFragment(object): + + # Standard files documentation fragment + DOCUMENTATION = r"""options: {} +notes: +- For more information on using Ansible to manage network devices see the :ref:`Ansible + Network Guide <network_guide>` +- For more information on using Ansible to manage Cisco devices see the `Cisco integration + page <https://www.ansible.com/integrations/networks/cisco>`_. +""" diff --git a/ansible_collections/cisco/iosxr/plugins/filter/__init__.py b/ansible_collections/cisco/iosxr/plugins/filter/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/filter/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/inventory/__init__.py b/ansible_collections/cisco/iosxr/plugins/inventory/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/inventory/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py new file mode 100644 index 00000000..58ff82be --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acl_interfaces/acl_interfaces.py @@ -0,0 +1,85 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_acl_interfaces module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Acl_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_acl_interfaces module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {"type": "str"}, + "config": { + "elements": "dict", + "options": { + "access_groups": { + "elements": "dict", + "options": { + "acls": { + "elements": "dict", + "options": { + "direction": { + "choices": ["in", "out"], + "type": "str", + "required": True, + }, + "name": {"type": "str", "required": True}, + }, + "type": "list", + }, + "afi": { + "choices": ["ipv4", "ipv6"], + "type": "str", + "required": True, + }, + }, + "type": "list", + }, + "name": {"type": "str", "required": True}, + }, + "type": "list", + }, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/acls.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/acls.py new file mode 100644 index 00000000..e8cb5f9c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/acls/acls.py @@ -0,0 +1,560 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_acls module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class AclsArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_acls module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {"type": "str"}, + "config": { + "elements": "dict", + "options": { + "acls": { + "elements": "dict", + "options": { + "name": {"type": "str"}, + "aces": { + "elements": "dict", + "mutually_exclusive": [ + ["grant", "remark", "line"], + ], + "options": { + "destination": { + "mutually_exclusive": [ + [ + "address", + "any", + "host", + "prefix", + "net_group", + "port_group", + ], + [ + "wildcard_bits", + "any", + "host", + "prefix", + "net_group", + "port_group", + ], + ], + "options": { + "host": {"type": "str"}, + "net_group": {"type": "str"}, + "port_group": {"type": "str"}, + "address": {"type": "str"}, + "any": {"type": "bool"}, + "prefix": {"type": "str"}, + "port_protocol": { + "mutually_exclusive": [ + [ + "eq", + "gt", + "lt", + "neq", + "range", + ], + ], + "options": { + "eq": {"type": "str"}, + "gt": {"type": "str"}, + "lt": {"type": "str"}, + "neq": {"type": "str"}, + "range": { + "options": { + "end": {"type": "str"}, + "start": { + "type": "str", + }, + }, + "required_together": [ + ["start", "end"], + ], + "type": "dict", + }, + }, + "type": "dict", + }, + "wildcard_bits": {"type": "str"}, + }, + "required_together": [ + ["address", "wildcard_bits"], + ], + "type": "dict", + }, + "dscp": { + "mutually_exclusive": [ + ["eq", "gt", "lt", "neq", "range"], + ], + "type": "dict", + "options": { + "eq": {"type": "str"}, + "gt": {"type": "str"}, + "lt": {"type": "str"}, + "neq": {"type": "str"}, + "range": { + "options": { + "end": {"type": "str"}, + "start": {"type": "str"}, + }, + "required_together": [ + ["start", "end"], + ], + "type": "dict", + }, + }, + }, + "fragments": {"type": "bool"}, + "capture": {"type": "bool"}, + "destopts": {"type": "bool"}, + "authen": {"type": "bool"}, + "routing": {"type": "bool"}, + "hop_by_hop": {"type": "bool"}, + "grant": { + "type": "str", + "choices": ["permit", "deny"], + }, + "icmp_off": {"type": "bool"}, + "log": {"type": "bool"}, + "log_input": {"type": "bool"}, + "line": {"type": "str", "aliases": ["ace"]}, + "packet_length": { + "mutually_exclusive": [ + ["eq", "lt", "neq", "range"], + ["eq", "gt", "neq", "range"], + ], + "options": { + "eq": {"type": "int"}, + "gt": {"type": "int"}, + "lt": {"type": "int"}, + "neq": {"type": "int"}, + "range": { + "options": { + "end": {"type": "int"}, + "start": {"type": "int"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "precedence": {"type": "str"}, + "protocol": {"type": "str"}, + "protocol_options": { + "mutually_exclusive": [ + ["icmp", "tcp", "igmp", "icmpv6"], + ], + "options": { + "icmpv6": { + "type": "dict", + "options": { + "address_unreachable": { + "type": "bool", + }, + "administratively_prohibited": { + "type": "bool", + }, + "beyond_scope_of_source_address": { + "type": "bool", + }, + "destination_unreachable": { + "type": "bool", + }, + "echo": {"type": "bool"}, + "echo_reply": {"type": "bool"}, + "erroneous_header_field": { + "type": "bool", + }, + "group_membership_query": { + "type": "bool", + }, + "group_membership_report": { + "type": "bool", + }, + "group_membership_termination": { + "type": "bool", + }, + "host_unreachable": { + "type": "bool", + }, + "nd_na": {"type": "bool"}, + "nd_ns": {"type": "bool"}, + "neighbor_redirect": { + "type": "bool", + }, + "no_route_to_destination": { + "type": "bool", + }, + "node_information_request_is_refused": { + "type": "bool", + }, + "node_information_successful_reply": { + "type": "bool", + }, + "packet_too_big": { + "type": "bool", + }, + "parameter_problem": { + "type": "bool", + }, + "port_unreachable": { + "type": "bool", + }, + "query_subject_is_IPv4address": { + "type": "bool", + }, + "query_subject_is_IPv6address": { + "type": "bool", + }, + "query_subject_is_domainname": { + "type": "bool", + }, + "reassembly_timeout": { + "type": "bool", + }, + "redirect": {"type": "bool"}, + "router_advertisement": { + "type": "bool", + }, + "router_renumbering": { + "type": "bool", + }, + "router_solicitation": { + "type": "bool", + }, + "rr_command": {"type": "bool"}, + "rr_result": {"type": "bool"}, + "rr_seqnum_reset": { + "type": "bool", + }, + "time_exceeded": { + "type": "bool", + }, + "ttl_exceeded": { + "type": "bool", + }, + "unknown_query_type": { + "type": "bool", + }, + "unreachable": { + "type": "bool", + }, + "unrecognized_next_header": { + "type": "bool", + }, + "unrecognized_option": { + "type": "bool", + }, + "whoareyou_reply": { + "type": "bool", + }, + "whoareyou_request": { + "type": "bool", + }, + }, + }, + "icmp": { + "options": { + "administratively_prohibited": { + "type": "bool", + }, + "alternate_address": { + "type": "bool", + }, + "conversion_error": { + "type": "bool", + }, + "dod_host_prohibited": { + "type": "bool", + }, + "dod_net_prohibited": { + "type": "bool", + }, + "echo": {"type": "bool"}, + "echo_reply": {"type": "bool"}, + "general_parameter_problem": { + "type": "bool", + }, + "host_isolated": { + "type": "bool", + }, + "host_precedence_unreachable": { + "type": "bool", + }, + "host_redirect": { + "type": "bool", + }, + "host_tos_redirect": { + "type": "bool", + }, + "host_tos_unreachable": { + "type": "bool", + }, + "host_unknown": { + "type": "bool", + }, + "host_unreachable": { + "type": "bool", + }, + "information_reply": { + "type": "bool", + }, + "information_request": { + "type": "bool", + }, + "mask_reply": {"type": "bool"}, + "mask_request": { + "type": "bool", + }, + "mobile_redirect": { + "type": "bool", + }, + "net_redirect": { + "type": "bool", + }, + "net_tos_redirect": { + "type": "bool", + }, + "net_tos_unreachable": { + "type": "bool", + }, + "net_unreachable": { + "type": "bool", + }, + "network_unknown": { + "type": "bool", + }, + "no_room_for_option": { + "type": "bool", + }, + "option_missing": { + "type": "bool", + }, + "packet_too_big": { + "type": "bool", + }, + "parameter_problem": { + "type": "bool", + }, + "port_unreachable": { + "type": "bool", + }, + "precedence_unreachable": { + "type": "bool", + }, + "protocol_unreachable": { + "type": "bool", + }, + "reassembly_timeout": { + "type": "bool", + }, + "redirect": {"type": "bool"}, + "router_advertisement": { + "type": "bool", + }, + "router_solicitation": { + "type": "bool", + }, + "source_quench": { + "type": "bool", + }, + "source_route_failed": { + "type": "bool", + }, + "time_exceeded": { + "type": "bool", + }, + "timestamp_reply": { + "type": "bool", + }, + "timestamp_request": { + "type": "bool", + }, + "traceroute": {"type": "bool"}, + "ttl_exceeded": { + "type": "bool", + }, + "unreachable": { + "type": "bool", + }, + }, + "type": "dict", + }, + "igmp": { + "options": { + "dvmrp": {"type": "bool"}, + "host_query": {"type": "bool"}, + "host_report": { + "type": "bool", + }, + "mtrace": {"type": "bool"}, + "mtrace_response": { + "type": "bool", + }, + "pim": {"type": "bool"}, + "trace": {"type": "bool"}, + }, + "type": "dict", + }, + "tcp": { + "options": { + "ack": {"type": "bool"}, + "established": { + "type": "bool", + }, + "fin": {"type": "bool"}, + "psh": {"type": "bool"}, + "rst": {"type": "bool"}, + "syn": {"type": "bool"}, + "urg": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "remark": {"type": "str"}, + "sequence": {"type": "int"}, + "source": { + "mutually_exclusive": [ + [ + "address", + "any", + "host", + "prefix", + "net_group", + "port_group", + ], + [ + "wildcard_bits", + "any", + "host", + "prefix", + "net_group", + "port_group", + ], + ], + "options": { + "host": {"type": "str"}, + "net_group": {"type": "str"}, + "port_group": {"type": "str"}, + "address": {"type": "str"}, + "any": {"type": "bool"}, + "prefix": {"type": "str"}, + "port_protocol": { + "mutually_exclusive": [ + [ + "eq", + "gt", + "lt", + "neq", + "range", + ], + ], + "options": { + "eq": {"type": "str"}, + "gt": {"type": "str"}, + "lt": {"type": "str"}, + "neq": {"type": "str"}, + "range": { + "options": { + "end": {"type": "str"}, + "start": { + "type": "str", + }, + }, + "required_together": [ + ["start", "end"], + ], + "type": "dict", + }, + }, + "type": "dict", + }, + "wildcard_bits": {"type": "str"}, + }, + "required_together": [ + ["address", "wildcard_bits"], + ], + "type": "dict", + }, + "ttl": { + "mutually_exclusive": [ + ["eq", "gt", "lt", "neq", "range"], + ], + "options": { + "eq": {"type": "int"}, + "gt": {"type": "int"}, + "lt": {"type": "int"}, + "neq": {"type": "int"}, + "range": { + "options": { + "end": {"type": "int"}, + "start": {"type": "int"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + }, + "type": "list", + }, + }, + "type": "list", + }, + "afi": { + "choices": ["ipv4", "ipv6"], + "required": True, + "type": "str", + }, + }, + "type": "list", + }, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/bgp_address_family.py new file mode 100644 index 00000000..7413c1ad --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_address_family/bgp_address_family.py @@ -0,0 +1,398 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_bgp_address_family module +""" + + +class Bgp_address_familyArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_bgp_address_family module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "type": "dict", + "options": { + "as_number": {"type": "str"}, + "address_family": { + "type": "list", + "elements": "dict", + "options": { + "afi": { + "type": "str", + "choices": [ + "ipv4", + "ipv6", + "l2vpn", + "link-state", + "vpnv4", + "vpnv6", + ], + }, + "safi": { + "type": "str", + "choices": [ + "flowspec", + "mdt", + "multicast", + "mvpn", + "rt-filter", + "tunnel", + "unicast", + "evpn", + "mspw", + "vpls-vpws", + "link-state", + ], + }, + "vrf": {"type": "str"}, + "additional_paths": { + "type": "str", + "choices": ["send", "receive"], + }, + "advertise_best_external": {"type": "bool"}, + "aggregate_address": { + "type": "list", + "elements": "dict", + "options": { + "value": {"type": "str"}, + "as_set": {"type": "bool"}, + "as_confed_set": {"type": "bool"}, + "summary_only": {"type": "bool"}, + "route_policy": {"type": "str"}, + }, + }, + "allocate_label": { + "type": "dict", + "options": { + "all": {"type": "bool"}, + "route_policy": {"type": "str"}, + }, + }, + "as_path_loopcheck_out_disable": {"type": "bool"}, + "bgp": { + "type": "dict", + "options": { + "attribute_download": {"type": "bool"}, + "bestpath": { + "type": "dict", + "options": { + "origin_as": { + "type": "dict", + "options": { + "use": { + "type": "dict", + "options": { + "validity": { + "type": "bool", + }, + }, + }, + "allow": { + "type": "dict", + "options": { + "invalid": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "client_to_client": { + "type": "dict", + "options": { + "reflection": { + "type": "dict", + "options": { + "cluster_id_disable": { + "type": "dict", + "options": { + "cluster_id": { + "type": "str", + }, + "disable": { + "type": "bool", + }, + }, + }, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "dampening": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "value": {"type": "int"}, + "route_policy": {"type": "str"}, + }, + }, + "label_delay": { + "type": "dict", + "options": { + "delay_second_parts": {"type": "int"}, + "delay_ms_parts": {"type": "int"}, + }, + }, + "import_delay": { + "type": "dict", + "options": { + "delay_second_parts": {"type": "int"}, + "delay_ms_parts": {"type": "int"}, + }, + }, + "origin_as": { + "type": "dict", + "options": { + "validation": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + "signal": { + "type": "dict", + "options": { + "ibgp": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "scan_time": {"type": "int"}, + }, + }, + "default_martian_check_disable": {"type": "bool"}, + "distance": { + "type": "dict", + "options": { + "routes_external_to_as": {"type": "int"}, + "routes_internal_to_as": {"type": "int"}, + "local_routes": {"type": "int"}, + }, + }, + "dynamic_med": {"type": "int"}, + "maximum_paths": { + "type": "dict", + "options": { + "ibgp": { + "type": "dict", + "options": { + "max_path_value": {"type": "int"}, + "order_igp_metric": {"type": "bool"}, + "selective_order_igp_metric": { + "type": "bool", + }, + "unequal_cost": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "order_igp_metric": { + "type": "bool", + }, + "selective_order_igp_metric": { + "type": "bool", + }, + }, + }, + }, + }, + "ebgp": { + "type": "dict", + "options": { + "max_path_value": {"type": "int"}, + "order_igp_metric": {"type": "bool"}, + "selective_order_igp_metric": { + "type": "bool", + }, + }, + }, + "eibgp": { + "type": "dict", + "options": { + "max_path_value": {"type": "int"}, + "order_igp_metric": {"type": "bool"}, + "selective_order_igp_metric": { + "type": "bool", + }, + }, + }, + }, + }, + "networks": { + "type": "list", + "elements": "dict", + "options": { + "network": {"type": "str"}, + "backdoor_route_policy": {"type": "str"}, + "route_policy": {"type": "str"}, + }, + }, + "nexthop": { + "type": "dict", + "options": { + "resolution_prefix_length_minimum": { + "type": "int", + "choices": [0, 32], + }, + "route_policy": {"type": "str"}, + "trigger_delay_critical": {"type": "int"}, + "trigger_delay_non_critical": {"type": "int"}, + }, + }, + "optimal_route_reflection": { + "type": "dict", + "options": { + "group_name": {"type": "str"}, + "primary_address": {"type": "str"}, + "secondary_address": {"type": "str"}, + }, + }, + "permanent_network_route_policy": {"type": "str"}, + "retain_local_label": {"type": "int"}, + "table_policy": {"type": "str"}, + "update": { + "type": "dict", + "options": { + "limit": { + "type": "dict", + "options": { + "sub_group": { + "type": "dict", + "options": { + "ibgp": {"type": "int"}, + "ebgp": {"type": "int"}, + }, + }, + "address_family": {"type": "int"}, + }, + }, + "wait_install": {"type": "bool"}, + }, + }, + "redistribute": { + "type": "list", + "elements": "dict", + "options": { + "protocol": { + "type": "str", + "choices": [ + "ospf", + "application", + "eigrp", + "isis", + "static", + "connected", + "lisp", + "mobile", + "rip", + "subscriber", + ], + "required": True, + }, + "id": {"type": "str"}, + "metric": {"type": "int"}, + "route_policy": {"type": "str"}, + "internal": {"type": "bool"}, + "external": {"type": "bool"}, + "level": { + "type": "str", + "choices": ["1", "2", "1-inter-area"], + }, + "nssa_external": {"type": "bool"}, + "external_ospf": { + "type": "int", + "choices": [1, 2], + }, + }, + }, + "inter_as_install": {"type": "bool"}, + "segmented_multicast": {"type": "bool"}, + "global_table_multicast": {"type": "bool"}, + "vrf_all_conf": { + "type": "dict", + "options": { + "source_rt_import_policy": {"type": "bool"}, + "table_policy": {"type": "str"}, + "label_mode": { + "type": "dict", + "options": { + "per_ce": {"type": "bool"}, + "per_vrf": {"type": "bool"}, + "route_policy": {"type": "str"}, + }, + }, + }, + }, + "weight": { + "type": "dict", + "options": { + "reset_on_import_disable": {"type": "bool"}, + "reset_on_import": {"type": "bool"}, + }, + }, + "allow_vpn_default_originate": {"type": "bool"}, + "label_mode": { + "type": "dict", + "options": { + "per_ce": {"type": "bool"}, + "per_vrf": {"type": "bool"}, + "route_policy": {"type": "str"}, + "per_prefix": {"type": "bool"}, + }, + }, + "mvpn_single_forwarder_selection_all": { + "type": "bool", + }, + "mvpn_single_forwarder_selection_highest_ip_address": { + "type": "bool", + }, + "route_target_download": {"type": "bool"}, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "deleted", + "merged", + "overridden", + "replaced", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/bgp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/bgp_global.py new file mode 100644 index 00000000..051e2699 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_global/bgp_global.py @@ -0,0 +1,1249 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_bgp_global module +""" + + +class Bgp_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_bgp_global module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "type": "dict", + "options": { + "as_number": {"type": "str"}, + "bfd": { + "type": "dict", + "options": { + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_path_loopcheck": {"type": "bool"}, + "auto_policy_soft_reset": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "bestpath": { + "type": "dict", + "options": { + "as_path": { + "type": "dict", + "options": { + "ignore": {"type": "bool"}, + "multipath_relax": {"type": "bool"}, + }, + }, + "aigp": { + "type": "dict", + "options": {"ignore": {"type": "bool"}}, + }, + "med": { + "type": "dict", + "options": { + "always": {"type": "bool"}, + "confed": {"type": "bool"}, + "missing_as_worst": {"type": "bool"}, + }, + }, + "compare_routerid": {"type": "bool"}, + "cost_community": { + "type": "dict", + "options": {"ignore": {"type": "bool"}}, + }, + "origin_as": { + "type": "dict", + "options": { + "use": { + "type": "dict", + "options": { + "validity": {"type": "bool"}, + }, + }, + "allow": { + "type": "dict", + "options": { + "invalid": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "cluster_id": {"type": "str"}, + "confederation": { + "type": "dict", + "options": { + "identifier": {"type": "int"}, + "peers": {"type": "list", "elements": "int"}, + }, + }, + "default": { + "type": "dict", + "options": {"local_preference": {"type": "int"}}, + }, + "enforce_first_as": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "fast_external_fallover": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "graceful_restart": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "graceful_reset": {"type": "bool"}, + "restart_time": {"type": "int"}, + "purge_time": {"type": "int"}, + "stalepath_time": {"type": "int"}, + }, + }, + "install": { + "type": "dict", + "options": {"diversion": {"type": "bool"}}, + }, + "log": { + "type": "dict", + "options": { + "log_message": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "neighbor": { + "type": "dict", + "options": { + "changes": { + "type": "dict", + "options": { + "detail": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "maximum": { + "type": "dict", + "options": {"neighbor": {"type": "int"}}, + }, + "multipath": { + "type": "dict", + "options": { + "as_path": { + "type": "dict", + "options": { + "ignore": { + "type": "dict", + "options": { + "onwards": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "origin_as": { + "type": "dict", + "options": { + "validation": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + "signal": { + "type": "dict", + "options": { + "ibgp": {"type": "bool"}, + }, + }, + "time": { + "type": "dict", + "options": { + "time_off": {"type": "bool"}, + "time_in_second": { + "type": "int", + }, + }, + }, + }, + }, + }, + }, + "redistribute_internal": {"type": "bool"}, + "router_id": {"type": "str"}, + "scan_time": {"type": "int"}, + "unsafe_ebgp_policy": {"type": "bool"}, + "update_delay": {"type": "int"}, + }, + }, + "default_information": { + "type": "dict", + "options": {"originate": {"type": "bool"}}, + }, + "default_metric": {"type": "int"}, + "graceful_maintenance": { + "type": "dict", + "options": { + "activate": { + "type": "str", + "choices": [ + "all-neighbors", + "retain-routes", + "all-neighbors retain-routes", + "", + ], + }, + }, + }, + "ibgp": { + "type": "dict", + "options": { + "policy": { + "type": "dict", + "options": { + "out": { + "type": "dict", + "options": { + "enforce_modifications": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "mpls": { + "type": "dict", + "options": { + "activate": { + "type": "dict", + "options": {"interface": {"type": "str"}}, + }, + }, + }, + "mvpn": {"type": "bool"}, + "neighbors": { + "type": "list", + "elements": "dict", + "options": { + "neighbor_address": { + "type": "str", + "aliases": ["neighbor"], + "required": True, + }, + "advertisement_interval": {"type": "int"}, + "bfd": { + "type": "dict", + "options": { + "fast_detect": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + "strict_mode": {"type": "bool"}, + }, + }, + "multiplier": {"type": "int"}, + "minimum_interval": {"type": "int"}, + }, + }, + "bmp_activate": { + "type": "dict", + "options": {"server": {"type": "int"}}, + }, + "capability": { + "type": "dict", + "options": { + "additional_paths": { + "type": "dict", + "options": { + "send": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + "receive": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "suppress": { + "type": "dict", + "options": { + "four_byte_AS": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + }, + }, + "all": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "cluster_id": {"type": "str"}, + "description": {"type": "str"}, + "dmz_link_bandwidth": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "dscp": {"type": "str"}, + "ebgp_multihop": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "mpls": {"type": "bool"}, + }, + }, + "ebgp_recv_extcommunity_dmz": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "ebgp_send_extcommunity_dmz": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "cumulatie": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "egress_engineering": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "enforce_first_as": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "graceful_maintenance": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "activate": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "as_prepends": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "value": {"type": "int"}, + }, + }, + "local_preference": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "graceful_restart": { + "type": "dict", + "options": { + "restart_time": {"type": "int"}, + "stalepath_time": {"type": "int"}, + }, + }, + "ignore_connected_check": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "keychain": { + "type": "dict", + "no_log": False, + "options": { + "name": {"type": "str"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "local": { + "type": "dict", + "options": { + "address": { + "type": "dict", + "options": { + "ipv4_address": {"type": "str"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "local_as": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "log": { + "type": "dict", + "options": { + "log_message": { + "type": "dict", + "options": { + "in": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "disable": {"type": "bool"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + "out": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "disable": {"type": "bool"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "origin_as": { + "type": "dict", + "options": { + "validation": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + }, + }, + "receive_buffer_size": {"type": "int"}, + "remote_as": {"type": "int"}, + "send_buffer_size": {"type": "int"}, + "session_open_mode": { + "type": "str", + "choices": ["active-only", "both", "passive-only"], + }, + "shutdown": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "tcp": { + "type": "dict", + "options": { + "mss": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "timers": { + "type": "dict", + "options": { + "keepalive_time": {"type": "int"}, + "holdtime": {"type": "int"}, + }, + }, + "ttl_security": { + "type": "dict", + "options": { + "inheritance_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "update": { + "type": "dict", + "options": { + "in": { + "type": "dict", + "options": { + "filtering": { + "type": "dict", + "options": { + "attribute_filter": { + "type": "dict", + "options": { + "group": { + "type": "str", + }, + }, + }, + "logging": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + }, + }, + }, + "update_message": { + "type": "dict", + "options": { + "buffers": { + "type": "int", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "update_source": {"type": "str"}, + }, + }, + "nsr": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + "socket": { + "type": "dict", + "options": { + "receive_buffer_size": {"type": "int"}, + "send_buffer_size": {"type": "int"}, + }, + }, + "timers": { + "type": "dict", + "options": { + "keepalive_time": {"type": "int"}, + "holdtime": {"type": "int"}, + }, + }, + "update": { + "type": "dict", + "options": { + "in": { + "type": "dict", + "options": { + "error_handling": { + "type": "dict", + "options": { + "basic": { + "type": "dict", + "options": { + "ebgp": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + }, + }, + }, + "ibgp": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + }, + }, + }, + }, + }, + "extended": { + "type": "dict", + "options": { + "ebgp": {"type": "bool"}, + "ibgp": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "out": { + "type": "dict", + "options": {"logging": {"type": "bool"}}, + }, + "limit": {"type": "int"}, + }, + }, + "rpki": { + "type": "dict", + "options": { + "route": { + "type": "dict", + "options": { + "value": {"type": "str"}, + "max": {"type": "int"}, + "origin": {"type": "int"}, + }, + }, + "servers": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "purge_time": {"type": "int"}, + "refresh_time": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "time_off": {"type": "bool"}, + }, + }, + "response_time": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "time_off": {"type": "bool"}, + }, + }, + "shutdown": {"type": "bool"}, + "transport": { + "type": "dict", + "options": { + "ssh": { + "type": "dict", + "options": { + "port": {"type": "int"}, + }, + }, + "tcp": { + "type": "dict", + "options": { + "port": {"type": "int"}, + }, + }, + }, + }, + }, + }, + }, + }, + "vrfs": { + "type": "list", + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "bfd": { + "type": "dict", + "options": { + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + }, + "bgp": { + "type": "dict", + "options": { + "auto_policy_soft_reset": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "bestpath": { + "type": "dict", + "options": { + "as_path": { + "type": "dict", + "options": { + "ignore": {"type": "bool"}, + "multipath_relax": { + "type": "bool", + }, + }, + }, + "aigp": { + "type": "dict", + "options": { + "ignore": {"type": "bool"}, + }, + }, + "med": { + "type": "dict", + "options": { + "always": {"type": "bool"}, + "confed": {"type": "bool"}, + "missing_as_worst": { + "type": "bool", + }, + }, + }, + "compare_routerid": {"type": "bool"}, + "cost_community": { + "type": "dict", + "options": { + "ignore": {"type": "bool"}, + }, + }, + "origin_as": { + "type": "dict", + "options": { + "use": { + "type": "dict", + "options": { + "validity": { + "type": "bool", + }, + }, + }, + "allow": { + "type": "dict", + "options": { + "invalid": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "default": { + "type": "dict", + "options": { + "local_preference": {"type": "int"}, + }, + }, + "enforce_first_as": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "fast_external_fallover": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "log": { + "type": "dict", + "options": { + "log_message": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + }, + }, + "neighbor": { + "type": "dict", + "options": { + "changes": { + "type": "dict", + "options": { + "detail": { + "type": "bool", + }, + "disable": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "multipath": { + "type": "dict", + "options": { + "as_path": { + "type": "dict", + "options": { + "ignore": { + "type": "dict", + "options": { + "onwards": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "redistribute_internal": {"type": "bool"}, + "router_id": {"type": "str"}, + "unsafe_ebgp_policy": {"type": "bool"}, + }, + }, + "default_information": { + "type": "dict", + "options": {"originate": {"type": "bool"}}, + }, + "default_metric": {"type": "int"}, + "mpls": { + "type": "dict", + "options": { + "activate": { + "type": "dict", + "options": {"interface": {"type": "str"}}, + }, + }, + }, + "neighbors": { + "type": "list", + "elements": "dict", + "options": { + "neighbor_address": { + "type": "str", + "aliases": ["neighbor"], + "required": True, + }, + "advertisement_interval": {"type": "int"}, + "bfd": { + "type": "dict", + "options": { + "fast_detect": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + "strict_mode": { + "type": "bool", + }, + }, + }, + "multiplier": {"type": "int"}, + "minimum_interval": {"type": "int"}, + }, + }, + "bmp_activate": { + "type": "dict", + "options": {"server": {"type": "int"}}, + }, + "capability": { + "type": "dict", + "options": { + "additional_paths": { + "type": "dict", + "options": { + "send": { + "type": "dict", + "options": { + "set": { + "type": "bool", + }, + "disable": { + "type": "bool", + }, + }, + }, + "receive": { + "type": "dict", + "options": { + "set": { + "type": "bool", + }, + "disable": { + "type": "bool", + }, + }, + }, + }, + }, + "suppress": { + "type": "dict", + "options": { + "four_byte_AS": { + "type": "dict", + "options": { + "set": { + "type": "bool", + }, + }, + }, + "all": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "cluster_id": {"type": "str"}, + "description": {"type": "str"}, + "dmz_link_bandwidth": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "dscp": {"type": "str"}, + "ebgp_multihop": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "mpls": {"type": "bool"}, + }, + }, + "ebgp_recv_extcommunity_dmz": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "ebgp_send_extcommunity_dmz": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "cumulatie": {"type": "bool"}, + "set": {"type": "bool"}, + }, + }, + "egress_engineering": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "enforce_first_as": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + "graceful_maintenance": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "activate": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "as_prepends": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "value": {"type": "int"}, + }, + }, + "local_preference": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "graceful_restart": { + "type": "dict", + "options": { + "restart_time": {"type": "int"}, + "stalepath_time": {"type": "int"}, + }, + }, + "ignore_connected_check": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "keychain": { + "type": "dict", + "no_log": False, + "options": { + "name": {"type": "str"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + "local": { + "type": "dict", + "options": { + "address": { + "type": "dict", + "options": { + "ipv4_address": { + "type": "str", + }, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "local_as": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + "log": { + "type": "dict", + "options": { + "log_message": { + "type": "dict", + "options": { + "in": { + "type": "dict", + "options": { + "value": { + "type": "int", + }, + "disable": { + "type": "bool", + }, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + "out": { + "type": "dict", + "options": { + "value": { + "type": "int", + }, + "disable": { + "type": "bool", + }, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + }, + }, + "origin_as": { + "type": "dict", + "options": { + "validation": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + }, + }, + }, + }, + "receive_buffer_size": {"type": "int"}, + "remote_as": {"type": "int"}, + "send_buffer_size": {"type": "int"}, + "session_open_mode": { + "type": "str", + "choices": [ + "active-only", + "both", + "passive-only", + ], + }, + "shutdown": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "tcp": { + "type": "dict", + "options": { + "mss": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "inheritance_disable": { + "type": "bool", + }, + }, + }, + }, + }, + "timers": { + "type": "dict", + "options": { + "keepalive_time": {"type": "int"}, + "holdtime": {"type": "int"}, + }, + }, + "ttl_security": { + "type": "dict", + "options": { + "inheritance_disable": { + "type": "bool", + }, + "set": {"type": "bool"}, + }, + }, + "update": { + "type": "dict", + "options": { + "in": { + "type": "dict", + "options": { + "filtering": { + "type": "dict", + "options": { + "attribute_filter": { + "type": "dict", + "options": { + "group": { + "type": "str", + }, + }, + }, + "logging": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + }, + }, + }, + "update_message": { + "type": "dict", + "options": { + "buffers": { + "type": "int", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "update_source": {"type": "str"}, + }, + }, + "rd": { + "type": "dict", + "options": {"auto": {"type": "bool"}}, + }, + "socket": { + "type": "dict", + "options": { + "receive_buffer_size": {"type": "int"}, + "send_buffer_size": {"type": "int"}, + }, + }, + "timers": { + "type": "dict", + "options": { + "keepalive_time": {"type": "int"}, + "holdtime": {"type": "int"}, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "deleted", + "merged", + "replaced", + "gathered", + "rendered", + "parsed", + "purged", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/bgp_neighbor_address_family.py new file mode 100644 index 00000000..a720860b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_neighbor_address_family/bgp_neighbor_address_family.py @@ -0,0 +1,438 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_bgp_neighbor_address_family module +""" + + +class Bgp_neighbor_address_familyArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_bgp_neighbor_address_family module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "type": "dict", + "options": { + "as_number": {"type": "str"}, + "neighbors": { + "type": "list", + "elements": "dict", + "options": { + "neighbor_address": {"type": "str", "required": True}, + "address_family": { + "type": "list", + "elements": "dict", + "options": { + "afi": { + "type": "str", + "choices": [ + "ipv4", + "ipv6", + "l2vpn", + "link-state", + "vpnv4", + "vpnv6", + ], + }, + "safi": { + "type": "str", + "choices": [ + "flowspec", + "mdt", + "multicast", + "mvpn", + "rt-filter", + "tunnel", + "unicast", + "labeled-unicast", + ], + }, + "aigp": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + "set": {"type": "bool"}, + "send_cost_community_disable": {"type": "bool"}, + "send_med": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "allowas_in": { + "type": "dict", + "options": {"value": {"type": "int"}, "set": {"type": "bool"}}, + }, + "as_override": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "bestpath_origin_as_allow_invalid": {"type": "bool"}, + "capability_orf_prefix": { + "type": "str", + "choices": ["both", "send", "none", "receive"], + }, + "default_originate": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "route_policy": {"type": "str"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "long_lived_graceful_restart": { + "type": "dict", + "options": { + "capable": {"type": "bool"}, + "stale_time": { + "type": "dict", + "options": { + "send": {"type": "int"}, + "accept": {"type": "int"}, + }, + }, + }, + }, + "maximum_prefix": { + "type": "dict", + "options": { + "max_limit": {"type": "int"}, + "threshold_value": {"type": "int"}, + "restart": {"type": "int"}, + "warning_only": {"type": "bool"}, + "discard_extra_paths": {"type": "bool"}, + }, + }, + "multipath": {"type": "bool"}, + "next_hop_self": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "next_hop_unchanged": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + "multipath": {"type": "bool"}, + }, + }, + "optimal_route_reflection_group_name": {"type": "str"}, + "orf_route_policy": {"type": "str"}, + "origin_as": { + "type": "dict", + "options": { + "validation": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + }, + }, + "remove_private_AS": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inbound": {"type": "bool"}, + "entire_aspath": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "route_policy": { + "type": "dict", + "options": { + "inbound": {"type": "str"}, + "outbound": {"type": "str"}, + }, + }, + "route_reflector_client": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_community_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_community_gshut_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_extended_community_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_multicast_attributes": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + "soft_reconfiguration": { + "type": "dict", + "options": { + "inbound": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "always": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + }, + }, + "weight": {"type": "int"}, + "validation": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "redirect": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "vrfs": { + "type": "list", + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "neighbors": { + "type": "list", + "elements": "dict", + "options": { + "neighbor_address": {"type": "str", "required": True}, + "address_family": { + "type": "list", + "elements": "dict", + "options": { + "afi": {"type": "str", "choices": ["ipv4", "ipv6"]}, + "safi": { + "type": "str", + "choices": [ + "flowspec", + "multicast", + "mvpn", + "unicast", + "labeled-unicast", + ], + }, + "aigp": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + "set": {"type": "bool"}, + "send_cost_community_disable": {"type": "bool"}, + "send_med": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "allowas_in": { + "type": "dict", + "options": { + "value": {"type": "int"}, + "set": {"type": "bool"}, + }, + }, + "as_override": { + "type": "dict", + "aliases": ["as_overrride"], + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "capability_orf_prefix": { + "type": "str", + "choices": ["both", "send", "none", "receive"], + }, + "default_originate": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "route_policy": {"type": "str"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "long_lived_graceful_restart": { + "type": "dict", + "options": { + "capable": {"type": "bool"}, + "stale_time": { + "type": "dict", + "options": { + "send": {"type": "int"}, + "accept": {"type": "int"}, + }, + }, + }, + }, + "maximum_prefix": { + "type": "dict", + "options": { + "max_limit": {"type": "int"}, + "threshold_value": {"type": "int"}, + "restart": {"type": "int"}, + "warning_only": {"type": "bool"}, + "discard_extra_paths": {"type": "bool"}, + }, + }, + "multipath": {"type": "bool"}, + "next_hop_self": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "next_hop_unchanged": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + "multipath": {"type": "bool"}, + }, + }, + "optimal_route_reflection_group_name": {"type": "str"}, + "orf_route_policy": {"type": "str"}, + "remove_private_AS": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inbound": {"type": "bool"}, + "entire_aspath": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "route_policy": { + "type": "dict", + "options": { + "inbound": {"type": "str"}, + "outbound": {"type": "str"}, + }, + }, + "route_reflector_client": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_community_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_community_gshut_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "send_extended_community_ebgp": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + "soft_reconfiguration": { + "type": "dict", + "options": { + "inbound": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "always": {"type": "bool"}, + "inheritance_disable": {"type": "bool"}, + }, + }, + }, + }, + "site_of_origin": {"type": "str"}, + "weight": {"type": "int"}, + "validation": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "redirect": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "deleted", + "merged", + "overridden", + "replaced", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/facts.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/facts.py new file mode 100644 index 00000000..478b9181 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/facts/facts.py @@ -0,0 +1,26 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The arg spec for the iosxr facts module. +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class FactsArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr facts module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "gather_subset": dict(default=["min"], type="list", elements="str"), + "gather_network_resources": dict(type="list", elements="str"), + "available_network_resources": {"type": "bool", "default": False}, + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/hostname.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/hostname.py new file mode 100644 index 00000000..04acd8a3 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/hostname/hostname.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_hostname module +""" + + +class HostnameArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_hostname module""" + + argument_spec = { + "config": {"type": "dict", "options": {"hostname": {"type": "str"}}}, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "deleted", + "merged", + "overridden", + "replaced", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/interfaces.py new file mode 100644 index 00000000..67b5c88c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/interfaces/interfaces.py @@ -0,0 +1,65 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the ios_interfaces module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class InterfacesArgs(object): + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "description": {"type": "str"}, + "enabled": {"default": True, "type": "bool"}, + "speed": {"type": "int"}, + "mtu": {"type": "int"}, + "duplex": {"type": "str", "choices": ["full", "half"]}, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py new file mode 100644 index 00000000..e58ddebb --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l2_interfaces/l2_interfaces.py @@ -0,0 +1,97 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_l2_interfaces module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class L2_InterfacesArgs(object): + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "native_vlan": {"type": "int"}, + "l2transport": {"type": "bool"}, + "l2protocol": { + "elements": "dict", + "options": { + "cdp": { + "type": "str", + "choices": ["drop", "forward", "tunnel"], + }, + "pvst": { + "type": "str", + "choices": ["drop", "forward", "tunnel"], + }, + "stp": { + "type": "str", + "choices": ["drop", "forward", "tunnel"], + }, + "vtp": { + "type": "str", + "choices": ["drop", "forward", "tunnel"], + }, + "cpsv": { + "type": "str", + "choices": ["drop", "reverse-tunnel", "tunnel"], + }, + }, + "type": "list", + }, + "q_vlan": {"type": "list", "elements": "int"}, + "propagate": {"type": "bool"}, + "encapsulation": { + "type": "dict", + "options": { + "dot1q": {"type": "int"}, + "second_dot1q": {"type": "int"}, + }, + }, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py new file mode 100644 index 00000000..bf506750 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/l3_interfaces/l3_interfaces.py @@ -0,0 +1,73 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the ios_l3_interfaces module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class L3_InterfacesArgs(object): + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "ipv4": { + "elements": "dict", + "type": "list", + "options": { + "address": {"type": "str"}, + "secondary": {"type": "bool"}, + }, + }, + "ipv6": { + "elements": "dict", + "type": "list", + "options": {"address": {"type": "str"}}, + }, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/lacp.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/lacp.py new file mode 100644 index 00000000..2bdda177 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp/lacp.py @@ -0,0 +1,69 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_lacp module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class LacpArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_lacp module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "options": { + "system": { + "options": { + "mac": { + "type": "dict", + "options": {"address": {"type": "str"}}, + }, + "priority": {"type": "int"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "deleted", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py new file mode 100644 index 00000000..55cdfda8 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lacp_interfaces/lacp_interfaces.py @@ -0,0 +1,77 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_lacp_interfaces module +""" + + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Lacp_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_lacp_interfaces module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "churn_logging": { + "choices": ["actor", "partner", "both"], + "type": "str", + }, + "collector_max_delay": {"type": "int"}, + "name": {"type": "str"}, + "period": {"type": "int"}, + "switchover_suppress_flaps": {"type": "int"}, + "system": { + "options": { + "mac": {"type": "str"}, + "priority": {"type": "int"}, + }, + "type": "dict", + }, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "deleted", + "overridden", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..09498c57 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lag_interfaces/lag_interfaces.py @@ -0,0 +1,88 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_lag_interfaces module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Lag_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_lag_interfaces module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "links": { + "options": { + "max_active": {"type": "int"}, + "min_active": {"type": "int"}, + }, + "type": "dict", + }, + "load_balancing_hash": { + "choices": ["dst-ip", "src-ip"], + "type": "str", + }, + "members": { + "elements": "dict", + "options": { + "member": {"type": "str"}, + "mode": { + "choices": ["on", "active", "passive", "inherit"], + "type": "str", + }, + }, + "type": "list", + }, + "mode": { + "choices": ["on", "active", "passive"], + "type": "str", + }, + "name": {"required": True, "type": "str"}, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py new file mode 100644 index 00000000..6c6c3947 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_global/lldp_global.py @@ -0,0 +1,73 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_lldp_global module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Lldp_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_lldp module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "options": { + "holdtime": {"type": "int"}, + "reinit": {"type": "int"}, + "subinterfaces": {"type": "bool"}, + "timer": {"type": "int"}, + "tlv_select": { + "options": { + "management_address": {"type": "bool"}, + "port_description": {"type": "bool"}, + "system_capabilities": {"type": "bool"}, + "system_description": {"type": "bool"}, + "system_name": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "deleted", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000..7eb13de6 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,77 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_lldp_interfaces module +""" + + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Lldp_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_lldp_interfaces module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "destination": { + "type": "dict", + "options": { + "mac_address": { + "type": "str", + "choices": [ + "ieee-nearest-bridge", + "ieee-nearest-non-tmpr-bridge", + ], + }, + }, + }, + "name": {"type": "str"}, + "receive": {"type": "bool"}, + "transmit": {"type": "bool"}, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "deleted", + "overridden", + "parsed", + "rendered", + "gathered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/logging_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/logging_global.py new file mode 100644 index 00000000..339ffc7e --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/logging_global/logging_global.py @@ -0,0 +1,429 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_logging_global module +""" + + +class Logging_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_logging_global module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "type": "dict", + "options": { + "archive": { + "type": "dict", + "options": { + "device": {"type": "str"}, + "archive_length": {"type": "int"}, + "archive_size": {"type": "int"}, + "file_size": {"type": "int"}, + "frequency": { + "type": "str", + "choices": ["daily", "weekly"], + }, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warnings", + ], + }, + "threshold": {"type": "int"}, + }, + }, + "buffered": { + "type": "dict", + "options": { + "size": {"type": "int"}, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warnings", + ], + }, + "discriminator": { + "type": "list", + "elements": "dict", + "options": { + "match_params": { + "type": "str", + "choices": [ + "match1", + "match2", + "match3", + "nomatch1", + "nomatch2", + "nomatch3", + ], + }, + "name": {"type": "str"}, + }, + }, + }, + }, + "console": { + "type": "dict", + "options": { + "state": { + "type": "str", + "choices": ["enabled", "disabled"], + }, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warning", + ], + }, + "discriminator": { + "type": "list", + "elements": "dict", + "options": { + "match_params": { + "type": "str", + "choices": [ + "match1", + "match2", + "match3", + "nomatch1", + "nomatch2", + "nomatch3", + ], + }, + "name": {"type": "str"}, + }, + }, + }, + }, + "correlator": { + "type": "dict", + "options": { + "buffer_size": {"type": "int"}, + "rules": { + "type": "list", + "elements": "dict", + "options": { + "rule_name": {"type": "str"}, + "rule_type": { + "type": "str", + "choices": ["stateful", "nonstateful"], + }, + "timeout": {"type": "int"}, + "timeout_rootcause": {"type": "int"}, + "context_correlation": {"type": "bool"}, + "reissue_nonbistate": {"type": "bool"}, + "reparent": {"type": "bool"}, + }, + }, + "rule_sets": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "rulename": { + "type": "list", + "elements": "str", + }, + }, + }, + }, + }, + "events": { + "type": "dict", + "options": { + "buffer_size": {"type": "int"}, + "display_location": {"type": "bool"}, + "filter_match": {"type": "list", "elements": "str"}, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warnings", + ], + }, + "threshold": {"type": "int"}, + }, + }, + "facility": { + "type": "str", + "choices": [ + "auth", + "cron", + "daemon", + "kern", + "local0", + "local1", + "local2", + "local3", + "local4", + "local5", + "local6", + "local7", + "lpr", + "mail", + "news", + "sys10", + "sys11", + "sys12", + "sys13", + "sys14", + "sys9", + "syslog", + "user", + "uucp", + ], + }, + "files": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "path": {"type": "str"}, + "maxfilesize": {"type": "int"}, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "info", + "notifications", + "warning", + ], + }, + }, + }, + "format": {"type": "bool"}, + "history": { + "type": "dict", + "options": { + "state": { + "type": "str", + "choices": ["enabled", "disabled"], + }, + "size": {"type": "int"}, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warnings", + ], + }, + }, + }, + "hostnameprefix": {"type": "str"}, + "ipv4": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": {"type": "str"}, + }, + }, + "ipv6": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": {"type": "str"}, + }, + }, + "localfilesize": {"type": "int"}, + "monitor": { + "type": "dict", + "options": { + "state": { + "type": "str", + "choices": ["enabled", "disabled"], + }, + "discriminator": { + "type": "list", + "elements": "dict", + "options": { + "match_params": { + "type": "str", + "choices": [ + "match1", + "match2", + "match3", + "nomatch1", + "nomatch2", + "nomatch3", + ], + }, + "name": {"type": "str"}, + }, + }, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warning", + ], + }, + }, + }, + "source_interfaces": { + "type": "list", + "elements": "dict", + "options": { + "interface": {"type": "str"}, + "vrf": {"type": "str"}, + }, + }, + "suppress": { + "type": "dict", + "options": { + "apply_rule": {"type": "str"}, + "duplicates": {"type": "bool"}, + }, + }, + "tls_servers": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warnings", + ], + }, + "tls_hostname": {"type": "str"}, + "trustpoint": {"type": "str"}, + "vrf": {"type": "str"}, + }, + }, + "trap": { + "type": "dict", + "options": { + "state": { + "type": "str", + "choices": ["enabled", "disabled"], + }, + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "errors", + "informational", + "notifications", + "warning", + ], + }, + }, + }, + "hosts": { + "type": "list", + "elements": "dict", + "options": { + "severity": { + "type": "str", + "choices": [ + "alerts", + "critical", + "debugging", + "emergencies", + "error", + "info", + "notifications", + "warning", + ], + }, + "host": {"type": "str"}, + "port": {"type": "str", "default": "default"}, + "vrf": {"type": "str", "default": "default"}, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/ntp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/ntp_global.py new file mode 100644 index 00000000..2c44713a --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ntp_global/ntp_global.py @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_ntp_global module +""" + + +class Ntp_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_ntp_global module""" + + argument_spec = { + "config": { + "type": "dict", + "options": { + "access_group": { + "type": "dict", + "options": { + "ipv4": { + "type": "dict", + "options": { + "peer": {"type": "str"}, + "query_only": {"type": "str"}, + "serve": {"type": "str"}, + "serve_only": {"type": "str"}, + }, + }, + "ipv6": { + "type": "dict", + "options": { + "peer": {"type": "str"}, + "query_only": {"type": "str"}, + "serve": {"type": "str"}, + "serve_only": {"type": "str"}, + }, + }, + "vrfs": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "ipv4": { + "type": "dict", + "options": { + "peer": {"type": "str"}, + "query_only": {"type": "str"}, + "serve": {"type": "str"}, + "serve_only": {"type": "str"}, + }, + }, + "ipv6": { + "type": "dict", + "options": { + "peer": {"type": "str"}, + "query_only": {"type": "str"}, + "serve": {"type": "str"}, + "serve_only": {"type": "str"}, + }, + }, + }, + }, + }, + }, + "authenticate": {"type": "bool"}, + "authentication_keys": { + "type": "list", + "elements": "dict", + "no_log": False, + "options": { + "id": {"type": "int"}, + "key": {"type": "str", "no_log": True}, + "encryption": {"type": "bool"}, + }, + }, + "broadcastdelay": {"type": "int"}, + "drift": { + "type": "dict", + "options": { + "aging_time": {"type": "int"}, + "file": {"type": "str"}, + }, + }, + "interfaces": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "vrf": {"type": "str"}, + "broadcast_client": {"type": "bool"}, + "broadcast_destination": {"type": "str"}, + "broadcast_key": {"type": "int", "no_log": False}, + "broadcast_version": {"type": "int"}, + "multicast_key": {"type": "int", "no_log": False}, + "multicast_ttl": {"type": "int"}, + "multicast_client": {"type": "str"}, + "multicast_destination": {"type": "str"}, + "multicast_version": {"type": "int"}, + }, + }, + "ipv4": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": { + "type": "str", + "choices": [ + "critical", + "flash", + "flash-override", + "immediate", + "internet", + "network", + "priority", + "routine", + ], + }, + }, + }, + "ipv6": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": { + "type": "str", + "choices": [ + "critical", + "flash", + "flash-override", + "immediate", + "internet", + "network", + "priority", + "routine", + ], + }, + }, + }, + "log_internal_sync": {"type": "bool"}, + "master": { + "type": "dict", + "options": {"stratum": {"type": "int"}}, + }, + "max_associations": {"type": "int"}, + "passive": {"type": "bool"}, + "trusted_keys": { + "type": "list", + "elements": "dict", + "no_log": False, + "options": {"key_id": {"type": "int"}}, + }, + "update_calendar": {"type": "bool"}, + "source_interface": {"type": "str"}, + "source_vrfs": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "vrf": {"type": "str"}, + }, + }, + "servers": { + "type": "list", + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "server": {"type": "str", "required": True}, + "burst": {"type": "bool"}, + "iburst": {"type": "bool"}, + "key_id": {"type": "int"}, + "source": {"type": "str"}, + "maxpoll": {"type": "int"}, + "minpoll": {"type": "int"}, + "prefer": {"type": "bool"}, + "version": {"type": "int"}, + }, + }, + "peers": { + "type": "list", + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "peer": {"type": "str", "required": True}, + "burst": {"type": "bool"}, + "iburst": {"type": "bool"}, + "key_id": {"type": "int"}, + "source": {"type": "str"}, + "maxpoll": {"type": "int"}, + "minpoll": {"type": "int"}, + "prefer": {"type": "bool"}, + "version": {"type": "int"}, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "deleted", + "merged", + "overridden", + "replaced", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/ospf_interfaces.py new file mode 100644 index 00000000..c74bde95 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospf_interfaces/ospf_interfaces.py @@ -0,0 +1,437 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_ospf_interfaces module +""" + + +class Ospf_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_ospf_interfaces module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {"type": "str"}, + "config": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "type": {"type": "str", "required": True}, + "address_family": { + "type": "list", + "elements": "dict", + "options": { + "afi": { + "type": "str", + "choices": ["ipv4", "ipv6"], + "required": True, + }, + "processes": { + "type": "list", + "elements": "dict", + "options": { + "process_id": { + "type": "str", + "required": True, + }, + "area": { + "type": "dict", + "options": {"area_id": {"type": "str"}}, + }, + }, + }, + "apply_group_option": { + "type": "dict", + "options": { + "group_name": {"type": "str"}, + "operation": { + "type": "str", + "choices": ["add", "remove", "append"], + }, + }, + }, + "authentication": { + "no_log": False, + "type": "dict", + "options": { + "message_digest": { + "no_log": False, + "type": "dict", + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + }, + }, + "null_auth": {"type": "bool"}, + }, + }, + "authentication_key": { + "type": "dict", + "no_log": True, + "options": { + "password": {"type": "str", "no_log": True}, + "clear": {"type": "str"}, + "encrypted": {"type": "str"}, + }, + }, + "bfd": { + "type": "dict", + "options": { + "fast_detect": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "strict_mode": {"type": "bool"}, + }, + }, + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + }, + "cost": {"type": "int"}, + "cost_fallback": { + "type": "dict", + "options": { + "cost": {"type": "int"}, + "threshold": {"type": "int"}, + }, + }, + "database_filter": { + "type": "dict", + "options": {"all_outgoing_lsa": {"type": "bool"}}, + }, + "dead_interval": {"type": "int"}, + "demand_circuit": {"type": "bool"}, + "fast_reroute": { + "type": "dict", + "options": { + "disabled": {"type": "bool"}, + "per_link": { + "type": "dict", + "options": { + "information_type": { + "type": "str", + "choices": [ + "exclude", + "lfa_candidate", + ], + }, + "use_candidate_only": {"type": "bool"}, + "interface": { + "type": "dict", + "options": { + "bvi": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "bundle_ether": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "pos_int": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "fast_ethernet": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "fiftygige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "fortygige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "fourhundredgige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "gigabitethernet": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "hundredgige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "mgmteth": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "multilink": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "pw_ether": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "pw_iw": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "srp": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "serial": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "tengige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "twentyfivegige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "twohundredgige": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + "nve": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "tunnel_ip": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "tunnel_ipsec": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "tunnel_mte": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "int", + }, + }, + }, + "tunnel_mpls": { + "type": "list", + "elements": "dict", + "options": { + "name": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "flood_reduction": {"type": "bool"}, + "hello_interval": {"type": "int"}, + "link_down_fast_detect": {"type": "bool"}, + "message_digest_key": { + "type": "dict", + "no_log": False, + "options": { + "id": {"type": "int", "required": True}, + "md5": { + "type": "dict", + "required": True, + "options": { + "password": { + "type": "str", + "no_log": True, + }, + "clear": {"type": "bool"}, + "encrypted": {"type": "bool"}, + }, + }, + }, + }, + "mpls_ldp_sync": {"type": "bool"}, + "mtu_ignore": {"type": "bool"}, + "network": { + "type": "str", + "choices": [ + "broadcast", + "non-broadcast", + "point-to-multipoint", + "point-to-point", + ], + }, + "neighbors": { + "type": "list", + "elements": "dict", + "options": { + "neighbor_id": {"type": "str"}, + "cost": {"type": "int"}, + "db_filter_all_out": {"type": "bool"}, + "poll_interval": {"type": "int"}, + "priority": {"type": "int"}, + }, + }, + "packet_size": {"type": "int"}, + "passive": {"type": "bool"}, + "prefix_suppression": {"type": "bool"}, + "priority": {"type": "int"}, + "retransmit_interval": {"type": "int"}, + "security_ttl": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "hops": {"type": "int"}, + }, + }, + "transmit_delay": {"type": "int"}, + }, + }, + }, + }, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/ospfv2.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/ospfv2.py new file mode 100644 index 00000000..b9b45461 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv2/ospfv2.py @@ -0,0 +1,825 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_ospfv2 module +""" +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Ospfv2Args(object): # pylint: disable=R0903 + """The arg spec for the iosxr_ospfv2 module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "options": { + "processes": { + "elements": "dict", + "options": { + "address_family_unicast": {"type": "bool"}, + "adjacency_stagger": { + "options": { + "disable": {"type": "bool"}, + "max_adjacency": {"type": "int"}, + "min_adjacency": {"type": "int"}, + }, + "required_together": [ + ["min_adjacency", "max_adjacency"], + ], + "type": "dict", + }, + "apply_weight": { + "mutually_exclusive": [ + ["bandwidth", "default_weight"], + ], + "options": { + "bandwidth": {"type": "int"}, + "default_weight": {"type": "int"}, + }, + "type": "dict", + }, + "areas": { + "elements": "dict", + "options": { + "area_id": {"required": True, "type": "str"}, + "authentication": { + "mutually_exclusive": [ + [ + "keychain", + "message_digest", + "no_auth", + ], + ], + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + "message_digest": { + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + }, + "type": "dict", + }, + "no_auth": {"type": "bool"}, + }, + "type": "dict", + }, + "authentication_key": { + "mutually_exclusive": [ + ["clear", "encrypted"], + ], + "options": { + "clear": {"type": "str"}, + "encrypted": {"type": "str"}, + "password": { + "type": "str", + "no_log": True, + }, + }, + "type": "dict", + "no_log": True, + }, + "bfd": { + "options": { + "fast_detect": { + "options": { + "set": {"type": "bool"}, + "strict_mode": { + "type": "bool", + }, + }, + "type": "dict", + }, + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + "type": "dict", + }, + "cost": {"type": "int"}, + "dead_interval": {"type": "int"}, + "default_cost": {"type": "int"}, + "hello_interval": {"type": "int"}, + "mpls": { + "options": { + "ldp": { + "options": { + "auto_config": { + "type": "bool", + }, + "sync": {"type": "bool"}, + "sync_igp_shortcuts": { + "type": "bool", + }, + }, + "type": "dict", + }, + "traffic_eng": {"type": "bool"}, + }, + "type": "dict", + }, + "mtu_ignore": { + "choices": ["enable", "disable"], + "type": "str", + }, + "nssa": { + "options": { + "default_information_originate": { + "options": { + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + }, + "type": "dict", + }, + "no_redistribution": {"type": "bool"}, + "no_summary": {"type": "bool"}, + "set": {"type": "bool"}, + "translate": { + "options": { + "type7": { + "options": { + "always": { + "type": "bool", + }, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "ranges": { + "elements": "dict", + "mutually_exclusive": [ + ["advertise", "not_advertise"], + ], + "options": { + "address": { + "required": True, + "type": "str", + }, + "advertise": {"type": "bool"}, + "not_advertise": {"type": "bool"}, + }, + "type": "list", + }, + "route_policy": { + "elements": "dict", + "options": { + "direction": { + "choices": ["in", "out"], + "type": "str", + }, + "parameters": { + "elements": "str", + "type": "list", + }, + }, + "type": "list", + }, + "stub": { + "options": { + "no_summary": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "transmit_delay": {"type": "int"}, + "virtual_link": { + "elements": "dict", + "options": { + "authentication": { + "mutually_exclusive": [ + [ + "keychain", + "message_digest", + "no_auth", + ], + ], + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + "message_digest": { + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + }, + "type": "dict", + }, + "no_auth": {"type": "bool"}, + }, + "type": "dict", + }, + "authentication_key": { + "mutually_exclusive": [ + ["clear", "encrypted"], + ], + "options": { + "clear": {"type": "str"}, + "encrypted": {"type": "str"}, + "password": { + "type": "str", + "no_log": True, + }, + }, + "type": "dict", + "no_log": True, + }, + "dead_interval": {"type": "int"}, + "hello_interval": {"type": "int"}, + "id": { + "required": True, + "type": "str", + }, + "message_digest_key": { + "options": { + "id": { + "required": True, + "type": "int", + }, + "md5": { + "mutually_exclusive": [ + ["clear", "encrypted"], + ], + "options": { + "clear": { + "type": "bool", + }, + "encrypted": { + "type": "bool", + }, + "password": { + "type": "str", + "no_log": True, + }, + }, + "type": "dict", + "no_log": False, + }, + }, + "type": "dict", + "no_log": False, + }, + "retransmit_interval": {"type": "int"}, + "transmit_delay": {"type": "int"}, + }, + "type": "list", + }, + }, + "type": "list", + }, + "authentication": { + "mutually_exclusive": [ + ["keychain", "message_digest", "no_auth"], + ], + "options": { + "keychain": {"type": "str", "no_log": False}, + "message_digest": { + "options": { + "keychain": { + "type": "str", + "no_log": False, + }, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "no_auth": {"type": "bool"}, + }, + "type": "dict", + }, + "authentication_key": { + "mutually_exclusive": [["clear", "encrypted"]], + "options": { + "clear": {"type": "bool"}, + "encrypted": {"type": "bool"}, + "password": {"type": "str", "no_log": True}, + }, + "type": "dict", + "no_log": True, + }, + "auto_cost": { + "mutually_exclusive": [ + ["reference_bandwidth", "disable"], + ], + "options": { + "disable": {"type": "bool"}, + "reference_bandwidth": {"type": "int"}, + }, + "type": "dict", + }, + "bfd": { + "options": { + "fast_detect": { + "options": { + "set": {"type": "bool"}, + "strict_mode": {"type": "bool"}, + }, + "type": "dict", + }, + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + "type": "dict", + }, + "capability": { + "options": { + "opaque": { + "mutually_exclusive": [["set", "disable"]], + "options": { + "disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "type7": {"type": "str"}, + }, + "type": "dict", + }, + "cost": {"type": "int"}, + "database_filter": { + "choices": ["enable", "disable"], + "type": "str", + }, + "dead_interval": {"type": "int"}, + "default_information_originate": { + "options": { + "always": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "default_metric": {"type": "int"}, + "demand_circuit": { + "choices": ["enable", "disable"], + "type": "str", + }, + "distance": { + "options": { + "admin_distance": { + "elements": "dict", + "options": { + "access_list": {"type": "str"}, + "source": {"type": "str"}, + "value": {"type": "int"}, + "wildcard": {"type": "str"}, + }, + "required_together": [ + ["value", "source", "wildcard"], + ], + "type": "list", + }, + "ospf_distance": { + "options": { + "external": {"type": "int"}, + "inter_area": {"type": "int"}, + "intra_area": {"type": "int"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "distribute_bgp_ls": { + "options": { + "instance_id": {"type": "int"}, + "throttle": {"type": "int"}, + }, + "type": "dict", + }, + "distribute_link_state": { + "options": { + "instance_id": {"type": "int"}, + "throttle": {"type": "int"}, + }, + "type": "dict", + }, + "distribute_list": { + "elements": "dict", + "mutually_exclusive": [ + ["access_list", "route_policy"], + ], + "options": { + "access_list": {"type": "str"}, + "direction": { + "choices": ["in", "out"], + "type": "str", + }, + "outgoing_params": { + "options": { + "id": {"type": "str"}, + "route_type": { + "choices": [ + "bgp", + "connected", + "dagr", + "ospf", + "static", + ], + "type": "str", + }, + }, + "type": "dict", + }, + "route_policy": {"type": "str"}, + }, + "type": "list", + }, + "external_out": { + "choices": ["enable", "disable"], + "type": "str", + }, + "flood_reduction": { + "choices": ["enable", "disable"], + "type": "str", + }, + "hello_interval": {"type": "int"}, + "ignore_lsa_mospf": {"type": "bool"}, + "link_down_fast_detect": {"type": "bool"}, + "log_adjacency_changes": { + "options": { + "detail": {"type": "bool"}, + "disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "loopback_stub_network": { + "choices": ["enable", "disable"], + "type": "str", + }, + "max_lsa": { + "options": { + "ignore_count": {"type": "int"}, + "ignore_time": {"type": "int"}, + "reset_time": {"type": "int"}, + "threshold": {"type": "int"}, + "warning_only": {"type": "bool"}, + }, + "type": "dict", + }, + "max_metric": { + "options": { + "router_lsa": { + "options": { + "external_lsa": { + "options": { + "max_metric_value": { + "type": "int", + }, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "include_stub": {"type": "bool"}, + "on_startup": { + "options": { + "set": {"type": "bool"}, + "wait_for_bgp_asn": { + "type": "int", + }, + "wait_period": {"type": "int"}, + }, + "type": "dict", + }, + "set": {"type": "bool"}, + "summary_lsa": { + "options": { + "max_metric_value": { + "type": "int", + }, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "message_digest_key": { + "options": { + "id": {"required": True, "type": "int"}, + "md5": { + "mutually_exclusive": [ + ["clear", "encrypted"], + ], + "options": { + "clear": {"type": "bool"}, + "encrypted": {"type": "bool"}, + "password": { + "type": "str", + "no_log": True, + }, + }, + "required": True, + "type": "dict", + "no_log": False, + }, + }, + "type": "dict", + "no_log": False, + }, + "microloop_avoidance": { + "mutually_exclusive": [ + [ + "protected", + "rib_update_delay", + "segment_routing", + ], + ], + "options": { + "protected": {"type": "bool"}, + "rib_update_delay": {"type": "int"}, + "segment_routing": {"type": "bool"}, + }, + "type": "dict", + }, + "monitor_convergence": { + "options": { + "prefix_list": {"type": "str"}, + "track_external_routes": {"type": "bool"}, + "track_ip_frr": {"type": "bool"}, + "track_summary_routes": {"type": "bool"}, + }, + "type": "dict", + }, + "mpls": { + "options": { + "ldp": { + "options": { + "auto_config": {"type": "bool"}, + "sync": {"type": "bool"}, + "sync_igp_shortcuts": {"type": "bool"}, + }, + "type": "dict", + }, + "traffic_eng": { + "options": { + "autoroute_exclude": { + "options": { + "parameters": { + "elements": "str", + "type": "list", + }, + "route_policy": { + "type": "str", + }, + }, + "type": "dict", + }, + "igp_intact": {"type": "bool"}, + "ldp_sync_update": {"type": "bool"}, + "multicast_intact": {"type": "bool"}, + "router_id": {"type": "str"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "mtu_ignore": { + "choices": ["enable", "disable"], + "type": "str", + }, + "network": { + "options": { + "broadcast": {"type": "bool"}, + "non_broadcast": {"type": "bool"}, + "point_to_multipoint": {"type": "bool"}, + "point_to_point": {"type": "bool"}, + }, + "type": "dict", + }, + "nsf": { + "options": { + "cisco": { + "options": { + "enforce_global": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "flush_delay_time": {"type": "int"}, + "ietf": { + "options": { + "helper_disable": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "interval": {"type": "int"}, + "lifetime": {"type": "int"}, + }, + "type": "dict", + }, + "nsr": {"type": "bool"}, + "packet_size": {"type": "int"}, + "passive": { + "choices": ["enable", "disable"], + "type": "str", + }, + "prefix_suppression": { + "options": { + "secondary_address": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "priority": {"type": "int"}, + "process_id": {"required": True, "type": "str"}, + "protocol_shutdown": { + "options": { + "host_mode": {"type": "bool"}, + "limit": { + "options": { + "high": {"type": "int"}, + "low": {"type": "int"}, + "medium": {"type": "int"}, + }, + "type": "dict", + }, + "on_reload": {"type": "bool"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "redistribute": { + "options": { + "id": {"type": "str"}, + "level": { + "choices": [1, 2, 12], + "type": "int", + }, + "lsa_type_summary": {"type": "bool"}, + "match": {"type": "str"}, + "metric": {"type": "int"}, + "metric_type": { + "choices": [1, 2], + "type": "int", + }, + "nssa_only": {"type": "bool"}, + "preserve_med": {"type": "bool"}, + "route_policy": { + "options": { + "name": {"type": "str"}, + "parameters": { + "elements": "str", + "type": "list", + }, + }, + "type": "dict", + }, + "route_type": { + "choices": [ + "application", + "bgp", + "connected", + "dagr", + "eigrp", + "isis", + "mobile", + "ospf", + "rip", + "static", + "subscriber", + ], + "type": "str", + }, + "tag": {"type": "int"}, + }, + "type": "dict", + }, + "retransmit_interval": {"type": "int"}, + "router_id": {"type": "str"}, + "security_ttl": { + "options": { + "hops": {"type": "int"}, + "set": {"type": "bool"}, + }, + "type": "dict", + }, + "summary_in": { + "choices": ["enable", "disable"], + "type": "str", + }, + "summary_prefix": { + "elements": "dict", + "options": { + "not_advertise": {"type": "bool"}, + "prefix": {"required": True, "type": "str"}, + "tag": {"type": "int"}, + }, + "type": "list", + }, + "timers": { + "options": { + "graceful_shutdown": { + "options": { + "initial_delay": {"type": "int"}, + "retain_routes": {"type": "int"}, + }, + "type": "dict", + }, + "lsa": { + "options": { + "group_pacing": {"type": "int"}, + "min_arrival": {"type": "int"}, + "refresh": {"type": "int"}, + }, + "type": "dict", + }, + "pacing_flood": {"type": "int"}, + "throttle": { + "options": { + "fast_reroute": {"type": "int"}, + "lsa_all": { + "options": { + "initial_delay": { + "type": "int", + }, + "max_delay": {"type": "int"}, + "min_delay": {"type": "int"}, + }, + "type": "dict", + }, + "spf": { + "options": { + "change_delay": { + "type": "int", + }, + "max_wait": {"type": "int"}, + "second_delay": { + "type": "int", + }, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "transmit_delay": {"type": "int"}, + "weight": {"type": "int"}, + }, + "type": "list", + }, + }, + "type": "dict", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/ospfv3.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/ospfv3.py new file mode 100644 index 00000000..a72599b9 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ospfv3/ospfv3.py @@ -0,0 +1,1439 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The arg spec for the iosxr_ospfv3 module +""" + + +class Ospfv3Args(object): # pylint: disable=R0903 + """The arg spec for the iosxr_ospfv3 module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "running_config": {"type": "str"}, + "config": { + "type": "dict", + "options": { + "processes": { + "type": "list", + "elements": "dict", + "options": { + "process_id": {"type": "str", "required": True}, + "address_family_unicast": {"type": "bool"}, + "authentication": { + "type": "dict", + "options": { + "disable": {"type": "bool", "default": False}, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "algorithim_type": { + "type": "str", + "choices": ["md5", "sha1"], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + "auto_cost": { + "type": "dict", + "options": { + "reference_bandwidth": {"type": "int"}, + "disable": {"type": "bool"}, + }, + }, + "bfd": { + "type": "dict", + "options": { + "fast_detect": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "strict_mode": {"type": "bool"}, + }, + }, + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + }, + "areas": { + "type": "list", + "elements": "dict", + "options": { + "area_id": {"type": "str", "required": True}, + "authentication": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + "default": False, + }, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "algorithim_type": { + "type": "str", + "choices": ["md5", "sha1"], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + "bfd": { + "type": "dict", + "options": { + "fast_detect": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "strict_mode": { + "type": "bool", + }, + }, + }, + "minimum_interval": {"type": "int"}, + "multiplier": {"type": "int"}, + }, + }, + "cost": {"type": "int"}, + "database_filter": { + "type": "dict", + "options": { + "all_outgoing_lsa": {"type": "bool"}, + }, + }, + "dead_interval": {"type": "int"}, + "default_cost": {"type": "int"}, + "demand_circuit": {"type": "bool"}, + "distrinbute_rib_prefix_list_name": { + "type": "str", + }, + "fast_reroute": { + "type": "dict", + "options": { + "disabled": {"type": "bool"}, + "per_link": { + "type": "dict", + "options": { + "information_type": { + "type": "str", + "choices": [ + "exclude", + "lfa_candidate", + ], + }, + "use_candidate_only": { + "type": "bool", + }, + "interface": { + "type": "dict", + "options": { + "bvi": { + "type": "list", + "elements": "int", + }, + "bundle_ether": { + "type": "list", + "elements": "int", + }, + "pos_int": { + "type": "list", + "elements": "int", + }, + "fast_ethernet": { + "type": "list", + "elements": "str", + }, + "fiftygige": { + "type": "list", + "elements": "str", + }, + "fortygige": { + "type": "list", + "elements": "str", + }, + "fourhundredgige": { + "type": "list", + "elements": "str", + }, + "gigabitethernet": { + "type": "list", + "elements": "str", + }, + "hundredgige": { + "type": "list", + "elements": "str", + }, + "mgmteth": { + "type": "list", + "elements": "str", + }, + "multilink": { + "type": "list", + "elements": "str", + }, + "pw_ether": { + "type": "list", + "elements": "int", + }, + "pw_iw": { + "type": "list", + "elements": "int", + }, + "srp": { + "type": "list", + "elements": "str", + }, + "serial": { + "type": "list", + "elements": "str", + }, + "tengige": { + "type": "list", + "elements": "str", + }, + "twentyfivegige": { + "type": "list", + "elements": "str", + }, + "twohundredgige": { + "type": "list", + "elements": "str", + }, + "nve": { + "type": "list", + "elements": "int", + }, + "tunnel_ip": { + "type": "list", + "elements": "int", + }, + "tunnel_ipsec": { + "type": "list", + "elements": "int", + }, + "tunnel_mte": { + "type": "list", + "elements": "int", + }, + "tunnel_mpls": { + "type": "int", + }, + }, + }, + }, + }, + "per_prefix": { + "type": "dict", + "options": { + "information_type": { + "type": "str", + "choices": [ + "exclude", + "lfa_candidate", + ], + }, + "use_candidate_only": { + "type": "bool", + }, + "interface": { + "type": "dict", + "options": { + "bvi": { + "type": "list", + "elements": "int", + }, + "bundle_ether": { + "type": "list", + "elements": "int", + }, + "pos_int": { + "type": "list", + "elements": "int", + }, + "fast_ethernet": { + "type": "list", + "elements": "str", + }, + "fiftygige": { + "type": "list", + "elements": "str", + }, + "fortygige": { + "type": "list", + "elements": "str", + }, + "fourhundredgige": { + "type": "list", + "elements": "str", + }, + "gigabitethernet": { + "type": "list", + "elements": "str", + }, + "hundredgige": { + "type": "list", + "elements": "str", + }, + "mgmteth": { + "type": "list", + "elements": "str", + }, + "multilink": { + "type": "list", + "elements": "str", + }, + "pw_ether": { + "type": "list", + "elements": "int", + }, + "pw_iw": { + "type": "list", + "elements": "int", + }, + "srp": { + "type": "list", + "elements": "str", + }, + "serial": { + "type": "list", + "elements": "str", + }, + "tengige": { + "type": "list", + "elements": "str", + }, + "twentyfivegige": { + "type": "list", + "elements": "str", + }, + "twohundredgige": { + "type": "list", + "elements": "str", + }, + "nve": { + "type": "list", + "elements": "int", + }, + "tunnel_ip": { + "type": "list", + "elements": "int", + }, + "tunnel_ipsec": { + "type": "list", + "elements": "int", + }, + "tunnel_mte": { + "type": "list", + "elements": "int", + }, + "tunnel_mpls": { + "type": "int", + }, + }, + }, + }, + }, + }, + }, + "flood_reduction": {"type": "bool"}, + "hello_interval": {"type": "int"}, + "instance_id": {"type": "int"}, + "mtu_ignore": {"type": "bool"}, + "mpls_ldp_sync": {"type": "bool"}, + "network": { + "type": "str", + "choices": [ + "broadcast", + "non-broadcast", + "point-to-multipoint", + "point-to-point", + ], + }, + "nssa": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "default_information_originate": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + }, + }, + "no_redistribution": {"type": "bool"}, + "no_summary": {"type": "bool"}, + "translate": { + "type": "dict", + "options": { + "type7": { + "type": "dict", + "options": { + "always": { + "type": "bool", + "required": True, + }, + }, + }, + }, + }, + }, + }, + "packet_size": {"type": "int"}, + "passive": {"type": "bool"}, + "prefix_suppression": {"type": "bool"}, + "priority": {"type": "int"}, + "ranges": { + "type": "list", + "elements": "dict", + "options": { + "address": { + "type": "str", + "required": True, + }, + "cost": {"type": "int"}, + "advertise": {"type": "bool"}, + "not_advertise": {"type": "bool"}, + }, + }, + "retransmit_interval": {"type": "int"}, + "stub": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "no_summary": {"type": "bool"}, + }, + }, + "transmit_delay": {"type": "int"}, + "virtual_link": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "str", + "required": True, + }, + "authentication": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + "default": False, + }, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "algorithim_type": { + "type": "str", + "choices": [ + "md5", + "sha1", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + "dead_interval": {"type": "int"}, + "hello_interval": {"type": "int"}, + "retransmit_interval": {"type": "int"}, + "transmit_delay": {"type": "int"}, + "encryption": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + "default": False, + }, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "esp": { + "type": "dict", + "options": { + "triple_des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "aes": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "192", + "256", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "null_encryption": { + "type": "dict", + "options": { + "authentication": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "md5", + "sha1", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "encryption": { + "type": "dict", + "options": { + "disable": { + "type": "bool", + "default": False, + }, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "esp": { + "type": "dict", + "options": { + "triple_des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "aes": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "192", + "256", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "null_encryption": { + "type": "dict", + "options": { + "authentication": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "md5", + "sha1", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "capability": { + "type": "dict", + "options": { + "type7": { + "type": "dict", + "options": { + "prefer": {"type": "bool"}, + "translate": {"type": "bool"}, + }, + }, + }, + }, + "cost": {"type": "int"}, + "database_filter": { + "type": "dict", + "options": {"all_outgoing_lsa": {"type": "bool"}}, + }, + "dead_interval": {"type": "int"}, + "default_information_originate": { + "type": "dict", + "options": { + "always": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + "set": {"type": "bool"}, + }, + }, + "default_metric": {"type": "int"}, + "demand_circuit": {"type": "bool"}, + "distance": { + "type": "dict", + "options": { + "admin_distance": {"type": "int"}, + "ospfv3_distance": { + "type": "dict", + "options": { + "external": {"type": "int"}, + "inter_area": {"type": "int"}, + "intra_area": {"type": "int"}, + }, + }, + }, + }, + "distribute_list": { + "type": "dict", + "options": { + "prefix_list": { + "type": "list", + "elements": "str", + "options": { + "name": {"type": "str"}, + "in": {"type": "bool"}, + "out": {"type": "bool"}, + }, + }, + }, + }, + "encryption": { + "type": "dict", + "options": { + "disable": {"type": "bool", "default": False}, + "ipsec": { + "type": "dict", + "options": { + "spi": {"type": "int"}, + "esp": { + "type": "dict", + "options": { + "triple_des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "aes": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "192", + "256", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "des": { + "type": "dict", + "options": { + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + "null_encryption": { + "type": "dict", + "options": { + "authentication": { + "type": "dict", + "options": { + "algorithim_type": { + "type": "str", + "choices": [ + "md5", + "sha1", + ], + }, + "key": { + "type": "str", + "no_log": False, + }, + "clear_key": { + "type": "str", + "no_log": False, + }, + "password_key": { + "type": "str", + "no_log": False, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "fast_reroute": { + "type": "dict", + "options": { + "disabled": {"type": "bool"}, + "per_link": { + "type": "dict", + "options": { + "information_type": { + "type": "str", + "choices": [ + "exclude", + "lfa_candidate", + ], + }, + "use_candidate_only": {"type": "bool"}, + "interface": { + "type": "dict", + "options": { + "bvi": { + "type": "list", + "elements": "int", + }, + "bundle_ether": { + "type": "list", + "elements": "int", + }, + "pos_int": { + "type": "list", + "elements": "int", + }, + "fast_ethernet": { + "type": "list", + "elements": "str", + }, + "fiftygige": { + "type": "list", + "elements": "str", + }, + "fortygige": { + "type": "list", + "elements": "str", + }, + "fourhundredgige": { + "type": "list", + "elements": "str", + }, + "gigabitethernet": { + "type": "list", + "elements": "str", + }, + "hundredgige": { + "type": "list", + "elements": "str", + }, + "mgmteth": { + "type": "list", + "elements": "str", + }, + "multilink": { + "type": "list", + "elements": "str", + }, + "pw_ether": { + "type": "list", + "elements": "int", + }, + "pw_iw": { + "type": "list", + "elements": "int", + }, + "srp": { + "type": "list", + "elements": "str", + }, + "serial": { + "type": "list", + "elements": "str", + }, + "tengige": { + "type": "list", + "elements": "str", + }, + "twentyfivegige": { + "type": "list", + "elements": "str", + }, + "twohundredgige": { + "type": "list", + "elements": "str", + }, + "nve": { + "type": "list", + "elements": "int", + }, + "tunnel_ip": { + "type": "list", + "elements": "int", + }, + "tunnel_ipsec": { + "type": "list", + "elements": "int", + }, + "tunnel_mte": { + "type": "list", + "elements": "int", + }, + "tunnel_mpls": {"type": "int"}, + }, + }, + }, + }, + "per_prefix": { + "type": "dict", + "options": { + "information_type": { + "type": "str", + "choices": [ + "exclude", + "lfa_candidate", + ], + }, + "use_candidate_only": {"type": "bool"}, + "interface": { + "type": "dict", + "options": { + "bvi": { + "type": "list", + "elements": "int", + }, + "bundle_ether": { + "type": "list", + "elements": "int", + }, + "post_int": { + "type": "list", + "elements": "int", + }, + "fast_ethernet": { + "type": "list", + "elements": "str", + }, + "fiftygige": { + "type": "list", + "elements": "str", + }, + "fortygige": { + "type": "list", + "elements": "str", + }, + "fourhundredgige": { + "type": "list", + "elements": "str", + }, + "gigabitethernet": { + "type": "list", + "elements": "str", + }, + "hundredgige": { + "type": "list", + "elements": "str", + }, + "mgmteth": { + "type": "list", + "elements": "str", + }, + "multilink": { + "type": "list", + "elements": "str", + }, + "pw_ether": { + "type": "list", + "elements": "int", + }, + "pw_iw": { + "type": "list", + "elements": "int", + }, + "srp": { + "type": "list", + "elements": "str", + }, + "serial": { + "type": "list", + "elements": "str", + }, + "tengige": { + "type": "list", + "elements": "str", + }, + "twentyfivegige": { + "type": "list", + "elements": "str", + }, + "twohundredgige": { + "type": "list", + "elements": "str", + }, + "nve": { + "type": "list", + "elements": "int", + }, + "tunnel_ip": { + "type": "list", + "elements": "int", + }, + "tunnel_ipsec": { + "type": "list", + "elements": "int", + }, + "tunnel_mte": { + "type": "list", + "elements": "int", + }, + "tunnel_mpls": {"type": "int"}, + }, + }, + }, + }, + }, + }, + "flood_reduction": {"type": "bool"}, + "graceful_restart": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "helper_disable": {"type": "bool"}, + "min_interval": {"type": "int"}, + "max_interval": {"type": "int"}, + }, + }, + "hello_interval": {"type": "int"}, + "ignore_mospf_type6_lsa": {"type": "bool"}, + "instance_id": {"type": "int"}, + "log_adjacency_changes": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "disable": {"type": "bool"}, + "detail": {"type": "bool"}, + }, + }, + "maximum": { + "type": "dict", + "options": { + "interfaces": {"type": "int"}, + "paths": {"type": "int"}, + "redistributed_prefixes": {"type": "int"}, + }, + }, + "mpls_ldp_sync": {"type": "bool"}, + "mtu_ignore": {"type": "bool"}, + "network": { + "type": "str", + "choices": [ + "broadcast", + "non-broadcast", + "point-to-multipoint", + "point-to-point", + ], + }, + "nsr": {"type": "bool"}, + "packet_size": {"type": "int"}, + "passive": {"type": "bool"}, + "prefix_suppression": {"type": "bool"}, + "priority": {"type": "int"}, + "protocol_shutdown": {"type": "bool"}, + "redistribute": { + "type": "dict", + "options": { + "application": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "str", + "required": True, + }, + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "bgp": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "preserved_med": {"type": "str"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "connected": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "eigrp": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "int", + "required": True, + }, + "set": {"type": "bool"}, + "match": { + "type": "str", + "choices": [ + "external", + "internal", + ], + }, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "isis": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "str", + "required": True, + }, + "set": {"type": "bool"}, + "level": { + "type": "str", + "choices": [ + "level-1", + "level-1-2", + "level-2", + ], + }, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "mobile": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "ospfv3": { + "type": "list", + "elements": "dict", + "options": { + "id": { + "type": "str", + "required": True, + }, + "set": {"type": "bool"}, + "match": { + "type": "dict", + "options": { + "external": { + "type": "int", + "choices": ["1", "2"], + }, + "nssa_external": { + "type": "int", + "choices": ["1", "2"], + }, + "internal": {"type": "bool"}, + }, + }, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "static": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + "subscriber": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + "metric_type": {"type": "int"}, + "route_policy": {"type": "str"}, + "tag": {"type": "int"}, + }, + }, + }, + }, + "retransmit_interval": {"type": "int"}, + "router_id": {"type": "str"}, + "spf_prefix_priority": { + "type": "dict", + "options": { + "disable": {"type": "bool"}, + "route_policy": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "value": {"type": "str"}, + }, + }, + }, + }, + "stub_router": { + "type": "dict", + "options": { + "router_lsa": { + "type": "dict", + "options": { + "advertise_with": { + "type": "str", + "choices": [ + "max-metric", + "r-bit", + "v6-bit", + ], + }, + "always": {"type": "bool"}, + "external_lsa": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + }, + }, + "include_stub": {"type": "bool"}, + "on_proc_migration": {"type": "int"}, + "on_proc_restart": {"type": "int"}, + "on_startup": { + "type": "dict", + "options": { + "time": {"type": "int"}, + "wait_for_bgp": { + "type": "bool", + }, + }, + }, + "on_switchover": {"type": "int"}, + "summary_lsa": { + "type": "dict", + "options": { + "set": {"type": "bool"}, + "metric": {"type": "int"}, + }, + }, + }, + }, + }, + }, + "summary_prefix": { + "type": "list", + "elements": "dict", + "options": { + "prefix": {"type": "str", "required": True}, + "not_advertise": {"type": "bool"}, + "tag": {"type": "int"}, + }, + }, + "timers": { + "type": "dict", + "options": { + "lsa_arrival": {"type": "int"}, + "pacing": { + "type": "dict", + "options": { + "flood": {"type": "int"}, + "lsa_group": {"type": "int"}, + "retransmission": {"type": "int"}, + }, + }, + "throttle": { + "type": "dict", + "options": { + "lsa": { + "type": "dict", + "options": { + "all_lsa_initial": { + "type": "int", + }, + "all_lsa_minimum": { + "type": "int", + }, + }, + }, + "spf": { + "type": "dict", + "options": { + "spf_initial": {"type": "int"}, + "spf_minimum": {"type": "int"}, + }, + }, + }, + }, + }, + }, + "trace": { + "type": "dict", + "options": { + "size": {"type": "str"}, + "value": {"type": "int"}, + }, + }, + "transmit_delay": {"type": "int"}, + }, + }, + }, + }, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/ping.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/ping.py new file mode 100644 index 00000000..6b0f04ce --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/ping/ping.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_ping module +""" + + +class PingArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_ping module""" + + argument_spec = { + "count": {"type": "int"}, + "afi": {"choices": ["ipv4", "ipv6"], "default": "ipv4", "type": "str"}, + "dest": {"required": True, "type": "str"}, + "df_bit": {"default": False, "type": "bool"}, + "sweep": {"default": False, "type": "bool"}, + "validate": {"default": False, "type": "bool"}, + "source": {"type": "str"}, + "size": {"type": "int"}, + "state": { + "choices": ["absent", "present"], + "default": "present", + "type": "str", + }, + "vrf": {"type": "str"}, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/prefix_lists.py new file mode 100644 index 00000000..f8e5a1da --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/prefix_lists/prefix_lists.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_prefix_lists module +""" + + +class Prefix_listsArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_prefix_lists module""" + + argument_spec = { + "running_config": {"type": "str"}, + "config": { + "type": "list", + "elements": "dict", + "options": { + "afi": {"type": "str", "choices": ["ipv4", "ipv6"]}, + "prefix_lists": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "entries": { + "type": "list", + "elements": "dict", + "options": { + "sequence": {"type": "int"}, + "action": { + "type": "str", + "choices": ["permit", "deny", "remark"], + }, + "description": {"type": "str"}, + "prefix": {"type": "str"}, + "eq": {"type": "int"}, + "ge": {"type": "int"}, + "le": {"type": "int"}, + }, + }, + }, + }, + }, + }, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "parsed", + "gathered", + "rendered", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/snmp_server.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/snmp_server.py new file mode 100644 index 00000000..a51f04c0 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/snmp_server/snmp_server.py @@ -0,0 +1,574 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the iosxr_snmp_server module +""" + + +class Snmp_serverArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_snmp_server module""" + + argument_spec = { + "config": { + "type": "dict", + "options": { + "chassis_id": {"type": "str"}, + "communities": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "acl_v4": {"type": "str"}, + "acl_v6": {"type": "str"}, + "ro": {"type": "bool"}, + "rw": {"type": "bool"}, + "sdrowner": {"type": "bool"}, + "systemowner": {"type": "bool"}, + "v4_acl": {"type": "str"}, + }, + }, + "community_maps": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "context": {"type": "str"}, + "security_name": {"type": "str"}, + "target_list": {"type": "str"}, + }, + }, + "correlator": { + "type": "dict", + "options": { + "buffer_size": {"type": "int"}, + "rules": { + "type": "list", + "elements": "dict", + "options": { + "rule_name": {"type": "str"}, + "timeout": {"type": "int"}, + }, + }, + "rule_sets": { + "type": "list", + "elements": "dict", + "options": {"name": {"type": "str"}}, + }, + }, + }, + "contact": {"type": "str"}, + "context": {"type": "list", "elements": "str"}, + "drop": { + "type": "dict", + "options": { + "unknown_user": {"type": "bool"}, + "report_IPv4": {"type": "str"}, + "report_IPv6": {"type": "str"}, + }, + }, + "engineid": { + "type": "dict", + "options": {"local": {"type": "str"}}, + }, + "groups": { + "type": "list", + "elements": "dict", + "options": { + "group": {"type": "str"}, + "version": { + "type": "str", + "choices": ["v1", "v3", "v2c"], + }, + "context": {"type": "str"}, + "notify": {"type": "str"}, + "read": {"type": "str"}, + "write": {"type": "str"}, + "acl_v4": {"type": "str", "aliases": ["Ipv4_acl"]}, + "acl_v6": {"type": "str", "aliases": ["Ipv6_acl"]}, + "v4_acl": {"type": "str"}, + }, + }, + "hosts": { + "type": "list", + "elements": "dict", + "options": { + "host": {"type": "str"}, + "community": {"type": "str"}, + "udp_port": {"type": "int"}, + "informs": {"type": "bool"}, + "traps": {"type": "bool"}, + "version": { + "type": "str", + "choices": ["1", "2c", "3"], + }, + }, + }, + "ifindex": {"type": "bool"}, + "ifmib": { + "type": "dict", + "options": { + "ifalias_long": {"type": "bool"}, + "internal_cache_max_duration": {"type": "int"}, + "ipsubscriber": {"type": "bool"}, + "stats": {"type": "bool"}, + }, + }, + "inform": { + "options": { + "pending": {"type": "int"}, + "retries": {"type": "int"}, + "timeout": {"type": "int"}, + }, + "type": "dict", + }, + "interfaces": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "notification_linkupdown_disable": {"type": "bool"}, + "index_persistent": {"type": "bool"}, + }, + }, + "ipv4": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": {"type": "str"}, + }, + }, + "ipv6": { + "type": "dict", + "options": { + "dscp": {"type": "str"}, + "precedence": {"type": "str"}, + }, + }, + "location": {"type": "str"}, + "logging_threshold_oid_processing": {"type": "int"}, + "logging_threshold_pdu_processing": {"type": "int"}, + "mib_bulkstat_max_procmem_size": {"type": "int"}, + "mib_object_lists": {"type": "list", "elements": "str"}, + "mib_schema": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "object_list": {"type": "str"}, + "poll_interval": {"type": "int"}, + }, + }, + "mib_bulkstat_transfer_ids": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "buffer_size": {"type": "int"}, + "enable": {"type": "bool"}, + "format_schemaASCI": {"type": "bool"}, + "retain": {"type": "int"}, + "retry": {"type": "int"}, + "schema": {"type": "str"}, + "transfer_interval": {"type": "int"}, + }, + }, + "mroutemib_send_all_vrf": {"type": "bool"}, + "notification_log_mib": { + "type": "dict", + "options": { + "GlobalSize": {"type": "int"}, + "default": {"type": "bool"}, + "disable": {"type": "bool"}, + "size": {"type": "int"}, + }, + }, + "oid_poll_stats": {"type": "bool"}, + "overload_control": { + "type": "dict", + "options": { + "overload_drop_time": {"type": "int"}, + "overload_throttle_rate": {"type": "int"}, + }, + }, + "packetsize": {"type": "int"}, + "queue_length": {"type": "int"}, + "targets": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str"}, + "host": {"type": "str"}, + "vrf": {"type": "str"}, + }, + }, + "throttle_time": {"type": "int"}, + "timeouts": { + "type": "dict", + "options": { + "duplicate": {"type": "int"}, + "inQdrop": {"type": "int"}, + "pdu_stats": {"type": "int"}, + "subagent": {"type": "int"}, + "threshold": {"type": "int"}, + }, + }, + "trap": { + "type": "dict", + "options": { + "authentication_vrf_disable": {"type": "bool"}, + "link_ietf": {"type": "bool"}, + "throttle_time": {"type": "int"}, + }, + }, + "trap_source": {"type": "str"}, + "trap_timeout": {"type": "int"}, + "traps": { + "type": "dict", + "options": { + "addrpool": { + "type": "dict", + "options": { + "low": {"type": "bool"}, + "high": {"type": "bool"}, + }, + }, + "bfd": {"type": "bool"}, + "bgp": { + "type": "dict", + "options": { + "cbgp2": {"type": "bool"}, + "updown": {"type": "bool"}, + }, + }, + "bulkstat_collection": {"type": "bool"}, + "bulkstat_transfer": {"type": "bool"}, + "bridgemib": {"type": "bool"}, + "copy_complete": {"type": "bool"}, + "cisco_entity_ext": {"type": "bool"}, + "config": {"type": "bool"}, + "diameter": { + "type": "dict", + "options": { + "peerdown": {"type": "bool"}, + "peerup": {"type": "bool"}, + "permanentfail": {"type": "bool"}, + "protocolerror": {"type": "bool"}, + "transientfail": {"type": "bool"}, + }, + }, + "entity": {"type": "bool"}, + "entity_redundancy": { + "type": "dict", + "options": { + "all": {"type": "bool"}, + "status": {"type": "bool"}, + "switchover": {"type": "bool"}, + }, + }, + "entity_state": { + "type": "dict", + "options": { + "operstatus": {"type": "bool"}, + "switchover": {"type": "bool"}, + }, + }, + "flash": { + "type": "dict", + "options": { + "insertion": {"type": "bool"}, + "removal": {"type": "bool"}, + }, + }, + "fru_ctrl": {"type": "bool"}, + "hsrp": {"type": "bool"}, + "ipsla": {"type": "bool"}, + "ipsec": { + "type": "dict", + "options": { + "start": {"type": "bool"}, + "stop": {"type": "bool"}, + }, + }, + "isakmp": { + "type": "dict", + "options": { + "start": {"type": "bool"}, + "stop": {"type": "bool"}, + }, + }, + "isis": { + "type": "dict", + "options": { + "adjacency_change": {"type": "bool"}, + "all": {"type": "bool"}, + "area_mismatch": {"type": "bool"}, + "attempt_to_exceed_max_sequence": { + "type": "bool", + }, + "authentication_failure": {"type": "bool"}, + "authentication_type_failure": { + "type": "bool", + }, + "corrupted_lsp_detected": {"type": "bool"}, + "database_overload": {"type": "bool"}, + "id_len_mismatch": {"type": "bool"}, + "lsp_error_detected": {"type": "bool"}, + "lsp_too_large_to_propagate": {"type": "bool"}, + "manual_address_drops": {"type": "bool"}, + "max_area_addresses_mismatch": { + "type": "bool", + }, + "orig_lsp_buff_size_mismatch": { + "type": "bool", + }, + "version_skew": {"type": "bool"}, + "own_lsp_purge": {"type": "bool"}, + "rejected_adjacency": {"type": "bool"}, + "protocols_supported_mismatch": { + "type": "bool", + }, + "sequence_number_skip": {"type": "bool"}, + }, + }, + "l2tun": { + "type": "dict", + "options": { + "pseudowire_status": {"type": "bool"}, + "sessions": {"type": "bool"}, + "tunnel_down": {"type": "bool"}, + "tunnel_up": {"type": "bool"}, + }, + }, + "l2vpn": { + "type": "dict", + "options": { + "all": {"type": "bool"}, + "cisco": {"type": "bool"}, + "vc_down": {"type": "bool"}, + "vc_up": {"type": "bool"}, + }, + }, + "msdp_peer_state_change": {"type": "bool"}, + "ntp": {"type": "bool"}, + "ospf": { + "type": "dict", + "options": { + "errors": { + "type": "dict", + "options": { + "bad_packet": {"type": "bool"}, + "authentication_failure": { + "type": "bool", + }, + "config_error": {"type": "bool"}, + "virt_bad_packet": {"type": "bool"}, + "virt_authentication_failure": { + "type": "bool", + }, + "virt_config_error": {"type": "bool"}, + }, + }, + "lsa": { + "type": "dict", + "options": { + "lsa_maxage": {"type": "bool"}, + "lsa_originate": {"type": "bool"}, + }, + }, + "retransmit": { + "type": "dict", + "options": { + "packets": {"type": "bool"}, + "virt_packets": {"type": "bool"}, + }, + }, + "state_change": { + "type": "dict", + "options": { + "if_state_change": {"type": "bool"}, + "neighbor_state_change": { + "type": "bool", + }, + "virtif_state_change": { + "type": "bool", + }, + "virtneighbor_state_change": { + "type": "bool", + }, + }, + }, + }, + }, + "ospfv3": { + "type": "dict", + "options": { + "errors": { + "type": "dict", + "options": { + "bad_packet": {"type": "bool"}, + "config_error": {"type": "bool"}, + "virt_bad_packet": {"type": "bool"}, + "virt_config_error": {"type": "bool"}, + }, + }, + "state_change": { + "type": "dict", + "options": { + "if_state_change": {"type": "bool"}, + "neighbor_state_change": { + "type": "bool", + }, + "virtif_state_change": { + "type": "bool", + }, + "virtneighbor_state_change": { + "type": "bool", + }, + "nssa_state_change": {"type": "bool"}, + "restart_status_change": { + "type": "bool", + }, + "restart_helper_status_change": { + "type": "bool", + }, + "restart_virtual_helper_status_change": { + "type": "bool", + }, + }, + }, + }, + }, + "power": {"type": "bool"}, + "rf": {"type": "bool"}, + "pim": { + "type": "dict", + "options": { + "interface_state_change": {"type": "bool"}, + "invalid_message_received": {"type": "bool"}, + "neighbor_change": {"type": "bool"}, + "rp_mapping_change": {"type": "bool"}, + }, + }, + "rsvp": { + "type": "dict", + "options": { + "all": {"type": "bool"}, + "lost_flow": {"type": "bool"}, + "new_flow": {"type": "bool"}, + }, + }, + "selective_vrf_download_role_change": {"type": "bool"}, + "sensor": {"type": "bool"}, + "snmp": { + "type": "dict", + "options": { + "authentication": {"type": "bool"}, + "linkdown": {"type": "bool"}, + "linkup": {"type": "bool"}, + "warmstart": {"type": "bool"}, + "coldstart": {"type": "bool"}, + }, + }, + "vrrp_events": {"type": "bool"}, + "syslog": {"type": "bool"}, + "subscriber": { + "type": "dict", + "options": { + "session_agg_access_interface": { + "type": "bool", + }, + "session_agg_node": {"type": "bool"}, + }, + }, + "system": {"type": "bool"}, + "vpls": { + "type": "dict", + "options": { + "all": {"type": "bool"}, + "full_clear": {"type": "bool"}, + "full_raise": {"type": "bool"}, + "status": {"type": "bool"}, + }, + }, + }, + }, + "users": { + "type": "list", + "elements": "dict", + "options": { + "user": {"type": "str"}, + "group": {"type": "str"}, + "acl_v4": {"type": "str", "aliases": ["Ipv4_acl"]}, + "acl_v6": {"type": "str", "aliases": ["Ipv6_acl"]}, + "SDROwner": {"type": "bool"}, + "SystemOwner": {"type": "bool"}, + "v4_acl": {"type": "str"}, + "version": { + "type": "str", + "choices": ["v1", "v2c", "v3"], + }, + }, + }, + "vrfs": { + "type": "list", + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "context": {"type": "list", "elements": "str"}, + "hosts": { + "type": "list", + "elements": "dict", + "options": { + "host": {"type": "str"}, + "community": {"type": "str"}, + "udp_port": {"type": "int"}, + "informs": {"type": "bool"}, + "traps": {"type": "bool"}, + "version": { + "type": "str", + "choices": ["1", "2c", "3"], + }, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "deleted", + "merged", + "overridden", + "replaced", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/static_routes.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/static_routes.py new file mode 100644 index 00000000..7b2cd025 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/static_routes/static_routes.py @@ -0,0 +1,103 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the iosxr_static_routes module +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +class Static_routesArgs(object): # pylint: disable=R0903 + """The arg spec for the iosxr_static_routes module""" + + def __init__(self, **kwargs): + pass + + argument_spec = { + "config": { + "elements": "dict", + "options": { + "vrf": {"type": "str"}, + "address_families": { + "elements": "dict", + "options": { + "afi": { + "choices": ["ipv4", "ipv6"], + "required": True, + "type": "str", + }, + "safi": { + "choices": ["unicast", "multicast"], + "required": True, + "type": "str", + }, + "routes": { + "elements": "dict", + "options": { + "dest": {"required": True, "type": "str"}, + "next_hops": { + "elements": "dict", + "options": { + "admin_distance": {"type": "int"}, + "description": {"type": "str"}, + "dest_vrf": {"type": "str"}, + "forward_router_address": { + "type": "str", + }, + "interface": {"type": "str"}, + "metric": {"type": "int"}, + "tag": {"type": "int"}, + "track": {"type": "str"}, + "tunnel_id": {"type": "int"}, + "vrflabel": {"type": "int"}, + }, + "type": "list", + }, + }, + "type": "list", + }, + }, + "type": "list", + }, + }, + "type": "list", + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py new file mode 100644 index 00000000..4f21c181 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acl_interfaces/acl_interfaces.py @@ -0,0 +1,123 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_acl_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.acl_interfaces import ( + Acl_interfacesTemplate, +) + + +class Acl_interfaces(ResourceModule): + """ + The iosxr_acl_interfaces class + """ + + def __init__(self, module): + super(Acl_interfaces, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="acl_interfaces", + tmplt=Acl_interfacesTemplate(), + ) + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.gen_config() + self.run_commands() + return self.result + + def gen_config(self): + """Select the appropriate function based on the state provided + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + # convert list of dicts to dicts of dicts + wantd = {entry["name"]: entry for entry in self.want} + haved = {entry["name"]: entry for entry in self.have} + + # turn all lists of dicts into dicts prior to merge + for entry in wantd, haved: + self._list_to_dict(entry) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = {k: v for k, v in haved.items() if k in wantd or not wantd} + wantd = {} + + # remove superfluous config + if self.state in ["overridden", "deleted"]: + for k, have in haved.items(): + if k not in wantd: + self._compare(want={}, have=have) + + for k, want in wantd.items(): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + begin = len(self.commands) + self._compare_lists(want=want, have=have) + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render(want or have, "interface", False), + ) + + def _compare_lists(self, want, have): + wdict = want.get("access_groups", {}) + hdict = have.get("access_groups", {}) + + for afi in ("ipv4", "ipv6"): + wacls = wdict.pop(afi, {}).pop("acls", {}) + hacls = hdict.pop(afi, {}).pop("acls", {}) + + for key, entry in wacls.items(): + if entry != hacls.pop(key, {}): + entry["afi"] = afi + self.addcmd(entry, "access_groups", False) + # remove remaining items in have for replaced + for entry in hacls.values(): + entry["afi"] = afi + self.addcmd(entry, "access_groups", True) + + def _list_to_dict(self, entry): + for item in entry.values(): + for ag in item.get("access_groups", []): + ag["acls"] = {subentry["direction"]: subentry for subentry in ag.get("acls", [])} + item["access_groups"] = { + subentry["afi"]: subentry for subentry in item.get("access_groups", []) + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/acls.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/acls.py new file mode 100644 index 00000000..9f9b1ea6 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/acls/acls.py @@ -0,0 +1,529 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_acls class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + remove_empties, + search_obj_in_list, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_dict, + is_ipv4_address, + prefix_to_address_wildcard, +) + + +class Acls(ConfigBase): + """ + The iosxr_acls class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["acls"] + + def __init__(self, module): + super(Acls, self).__init__(module) + + def get_acls_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + acls_facts = facts["ansible_network_resources"].get("acls") + if not acls_facts: + return [] + return acls_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_acls_facts = self.get_acls_facts() + else: + existing_acls_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_acls_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_acls_facts = self.get_acls_facts() + + 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_acls_facts(data=running_config) + + if self.state in self.ACTION_STATES: + result["before"] = existing_acls_facts + if result["changed"]: + result["after"] = changed_acls_facts + + elif self.state == "gathered": + result["gathered"] = changed_acls_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_acls_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_acls_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + state = self._module.params["state"] + commands = [] + + if state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "overridden": + commands.extend(self._state_overridden(want, have)) + + elif state == "deleted": + commands.extend(self._state_deleted(want, have)) + + else: + # Instead of passing entire want and have + # list of dictionaries to the respective + # _state_* methods we are passing the want + # and have dictionaries per AFI + for item in want: + afi = item["afi"] + obj_in_have = search_obj_in_list(afi, have, key="afi") or {} + + if state == "merged" or self.state == "rendered": + commands.extend( + self._state_merged(remove_empties(item), obj_in_have), + ) + + elif state == "replaced": + commands.extend( + self._state_replaced( + remove_empties(item), + obj_in_have, + ), + ) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for want_acl in want["acls"]: + have_acl = search_obj_in_list(want_acl["name"], have.get("acls", [])) or {} + acl_updates = [] + + for have_ace in have_acl.get("aces", []): + want_ace = ( + search_obj_in_list( + have_ace["sequence"], + want_acl["aces"], + key="sequence", + ) + or {} + ) + if not want_ace: + acl_updates.append("no {0}".format(have_ace["sequence"])) + + for want_ace in want_acl.get("aces", []): + have_ace = ( + search_obj_in_list( + want_ace.get("sequence"), + have_acl.get("aces", []), + key="sequence", + ) + or {} + ) + set_cmd = self._set_commands(want_ace, have_ace) + if set_cmd: + acl_updates.append(set_cmd) + + if acl_updates: + acl_updates.insert( + 0, + "{0} access-list {1}".format( + want["afi"], + want_acl["name"], + ), + ) + commands.extend(acl_updates) + + return commands + + def _state_overridden(self, want, have): + """The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + # Remove extraneous AFI that are present in config but not + # specified in `want` + for have_afi in have: + want_afi = search_obj_in_list(have_afi["afi"], want, key="afi") or {} + if not want_afi: + for acl in have_afi.get("acls", []): + commands.append( + "no {0} access-list {1}".format( + have_afi["afi"], + acl["name"], + ), + ) + + # First we remove the extraneous ACLs from the AFIs that + # are present both in `want` and in `have` and then + # we call `_state_replaced` to update the ACEs within those ACLs + for want_afi in want: + want_afi = remove_empties(want_afi) + have_afi = search_obj_in_list(want_afi["afi"], have, key="afi") or {} + if have_afi: + for have_acl in have_afi.get("acls", []): + want_acl = ( + search_obj_in_list( + have_acl["name"], + want_afi.get("acls", []), + ) + or {} + ) + if not want_acl: + commands.append( + "no {0} access-list {1}".format( + have_afi["afi"], + have_acl["name"], + ), + ) + + commands.extend(self._state_replaced(want_afi, have_afi)) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + if not have: + have = {} + + for want_acl in want["acls"]: + have_acl = search_obj_in_list(want_acl["name"], have.get("acls", {})) or {} + + acl_updates = [] + for want_ace in want_acl["aces"]: + have_ace = ( + search_obj_in_list( + want_ace.get("sequence"), + have_acl.get("aces", []), + key="sequence", + ) + or {} + ) + set_cmd = self._set_commands(want_ace, have_ace) + if set_cmd: + acl_updates.append(set_cmd) + + if acl_updates: + acl_updates.insert( + 0, + "{0} access-list {1}".format( + want["afi"], + want_acl["name"], + ), + ) + commands.extend(acl_updates) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if not want: + want = [{"afi": "ipv4"}, {"afi": "ipv6"}] + + for item in want: + item = remove_empties(item) + have_item = search_obj_in_list(item["afi"], have, key="afi") or {} + if "acls" not in item: + if have_item: + for acl in have_item["acls"]: + commands.append( + "no {0} access-list {1}".format( + have_item["afi"], + acl["name"], + ), + ) + else: + for want_acl in item["acls"]: + have_acl = ( + search_obj_in_list( + want_acl["name"], + have_item.get("acls", []), + ) + or {} + ) + if have_acl: + commands.append( + "no {0} access-list {1}".format( + have_item["afi"], + have_acl["name"], + ), + ) + + return commands + + def _compute_commands(self, want_ace): + """This command creates an ACE line from an ACE dictionary + + :rtype: A string + :returns: An ACE generated from a structured ACE dictionary + """ + + def _compute_src_dest(dir_dict): + cmd = "" + if "any" in dir_dict: + cmd += "any " + elif "host" in dir_dict: + cmd += "host {0} ".format(dir_dict["host"]) + elif "net_group" in dir_dict: + cmd += "net-group {0} ".format(dir_dict["net_group"]) + elif "port_group" in dir_dict: + cmd += "port-group {0} ".format(dir_dict["port_group"]) + elif "prefix" in dir_dict: + cmd += "{0} ".format(dir_dict["prefix"]) + else: + cmd += "{0} {1} ".format( + dir_dict["address"], + dir_dict["wildcard_bits"], + ) + + if "port_protocol" in dir_dict: + protocol_range = dir_dict["port_protocol"].get("range") + if protocol_range: + cmd += "range {0} {1} ".format( + protocol_range["start"], + protocol_range["end"], + ) + else: + for key, value in iteritems(dir_dict["port_protocol"]): + cmd += "{0} {1} ".format(key, value) + + return cmd + + def _compute_protocol_options(protocol_dict): + cmd = "" + for value in protocol_options.values(): + for subkey, subvalue in iteritems(value): + if subvalue: + cmd += "{0} ".format(subkey.replace("_", "-")) + return cmd + + def _compute_match_options(want_ace): + cmd = "" + + if "precedence" in want_ace: + cmd += "precedence {0} ".format(want_ace["precedence"]) + + for x in ["dscp", "packet_length", "ttl"]: + if x in want_ace: + opt_range = want_ace[x].get("range") + if opt_range: + cmd += "{0} range {1} {2} ".format( + x.replace("_", "-"), + opt_range["start"], + opt_range["end"], + ) + else: + for key, value in iteritems(want_ace[x]): + cmd += "{0} {1} {2} ".format( + x.replace("_", "-"), + key, + value, + ) + + for x in ( + "authen", + "capture", + "fragments", + "routing", + "log", + "log_input", + "icmp_off", + "destopts", + "hop_by_hop", + ): + if x in want_ace: + cmd += "{0} ".format(x.replace("_", "-")) + + return cmd + + cmd = "" + if "sequence" in want_ace: + cmd += "{0} ".format(want_ace["sequence"]) + + if "remark" in want_ace: + cmd += "remark {0}".format(want_ace["remark"]) + + elif "line" in want_ace: + cmd += want_ace["line"] + + else: + cmd += "{0} ".format(want_ace["grant"]) + if "protocol" in want_ace: + cmd += "{0} ".format(want_ace["protocol"]) + + cmd += _compute_src_dest(want_ace["source"]) + cmd += _compute_src_dest(want_ace["destination"]) + + protocol_options = want_ace.get("protocol_options", {}) + if protocol_options: + cmd += _compute_protocol_options(protocol_options) + + cmd += _compute_match_options(want_ace) + + return cmd.strip() + + def _set_commands(self, want_ace, have_ace): + """A helped method that checks if there is + a delta between the `have_ace` and `want_ace`. + If there is a delta then it calls `_compute_commands` + to create the ACE line. + + :rtype: A string + :returns: An ACE generated from a structured ACE dictionary + via a call to `_compute_commands` + """ + + if "line" in want_ace: + if want_ace["line"] != have_ace.get("line"): + return self._compute_commands(want_ace) + + else: + if ("prefix" in want_ace.get("source", {})) or ( + "prefix" in want_ace.get("destination", {}) + ): + self._prepare_for_diff(want_ace) + + protocol_opt_delta = {} + delta = dict_diff(have_ace, want_ace) + + # `dict_diff` doesn't work properly for `protocol_options` diff, + # so we need to handle it separately + if want_ace.get("protocol_options", {}): + protocol_opt_delta = set( + flatten_dict(have_ace.get("protocol_options", {})), + ) ^ set(flatten_dict(want_ace.get("protocol_options", {}))) + + if delta or protocol_opt_delta: + want_ace = self._dict_merge(have_ace, want_ace) + return self._compute_commands(want_ace) + + def _prepare_for_diff(self, ace): + """This method prepares the want ace dict + for diff calculation against the have ace dict. + + :param ace: The want ace to prepare for diff calculation + """ + # Convert prefixes to "address wildcard bits" format for IPv4 addresses + # Not valid for IPv6 addresses because those can only be specified as prefixes + # and are always rendered in running-config as prefixes too + for x in ["source", "destination"]: + prefix = ace.get(x, {}).get("prefix") + if prefix and is_ipv4_address(prefix): + del ace[x]["prefix"] + ( + ace[x]["address"], + ace[x]["wildcard_bits"], + ) = prefix_to_address_wildcard(prefix) + + def _dict_merge(self, have_ace, want_ace): + for x in want_ace: + have_ace[x] = want_ace[x] + return have_ace diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/bgp_address_family.py new file mode 100644 index 00000000..6f090192 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_address_family/bgp_address_family.py @@ -0,0 +1,243 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_bgp_address_family config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_address_family import ( + Bgp_address_familyTemplate, +) + + +class Bgp_address_family(ResourceModule): + """ + The iosxr_bgp_address_family config class + """ + + def __init__(self, module): + super(Bgp_address_family, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="bgp_address_family", + tmplt=Bgp_address_familyTemplate(), + ) + self.parsers = [ + "router", + "address_family", + "advertise_best_external", + "additional_paths", + "allocate_label", + "as_path_loopcheck_out_disable", + "bgp_attribute_download", + "bgp_bestpath_origin_as_use", + "bgp_bestpath_origin_as_allow", + "bgp_client_to_client_reflection_cluster_id", + "bgp_reflection_disable", + "bgp_dampening", + "bgp_label_delay", + "bgp_import_delay", + "bgp_origin_as_validation", + "bgp_scan_time", + "default_martian_check_disable", + "distance", + "dynamic_med", + "maximum_paths_ibgp", + "maximum_paths_ebgp", + "maximum_paths_eibgp", + "optimal_route_reflection", + "nexthop", + "permanent_network_route_policy", + "retain_local_label", + "update", + "global_table_multicast", + "segmented_multicast", + "inter_as_install", + "vrf_all_conf", + "weight", + "route_target_download", + "label_mode", + "mvpn_single_forwarder_selection_highest_ip_address", + "mvpn_single_forwarder_selection_all", + "table_policy", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self.want + haved = self.have + for entry in self.want, self.have: + self._bgp_list_to_dict(entry) + + # if state is deleted, clean up global params + if self.state == "deleted": + if wantd: + to_del = {"address_family": self._set_to_delete(haved, wantd)} + haved.update(to_del) + + wantd = {"as_number": haved.get("as_number")} + + else: + wantd = self.want + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(self.have, self.want) + + self._compare(want=wantd, have=haved) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global network resource. + """ + + self._compare_af(want=want, have=have) + if self.commands and "router bgp" not in self.commands[0]: + self.commands.insert( + 0, + self._tmplt.render( + {"as_number": want["as_number"]}, + "router", + False, + ), + ) + + def _compare_af(self, want, have): + """Custom handling of afs option + :params want: the want BGP dictionary + :params have: the have BGP dictionary + """ + wafs = want.get("address_family", {}) + hafs = have.get("address_family", {}) + vrf_want_have = [] + for name, entry in iteritems(wafs): + begin = len(self.commands) + af_have = hafs.pop(name, {}) + if "vrf" in entry: + vrf_want_have.append((entry, af_have)) + + else: + self.compare(parsers=self.parsers, want=entry, have=af_have) + self._compare_lists(want=entry, have=af_have) + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render( + { + "afi": entry.get("afi"), + "safi": entry.get("safi"), + }, + "address_family", + False, + ), + ) + + # compare af under vrf separately to ensure correct generation of commands + for waf, haf in vrf_want_have: + begin = len(self.commands) + self.compare(parsers=self.parsers, want=waf, have=haf) + self._compare_lists(want=waf, have=haf) + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render( + {"afi": waf.get("afi"), "safi": waf.get("safi")}, + "address_family", + False, + ), + ) + self.commands.insert( + begin, + self._tmplt.render({"vrf": waf.get("vrf")}, "vrf", False), + ) + + # for deleted and overridden state + if self.state != "replaced": + for name, entry in iteritems(hafs): + if "vrf" in entry: + self.addcmd({"vrf": entry.get("vrf")}, "vrf", False) + self.addcmd( + {"afi": entry.get("afi"), "safi": entry.get("safi")}, + "address_family", + True, + ) + + def _compare_lists(self, want, have): + for attrib in ["aggregate_address", "networks", "redistribute"]: + wdict = want.get(attrib, {}) + hdict = have.get(attrib, {}) + for key, entry in iteritems(wdict): + if entry != hdict.pop(key, {}): + self.addcmd(entry, attrib.format(attrib), False) + + # remove remaining items in have for replaced + for entry in hdict.values(): + self.addcmd(entry, attrib.format(attrib), True) + + def _bgp_list_to_dict(self, entry): + """Convert list of items to dict of items + for efficient diff calculation. + :params entry: data dictionary + """ + for item in entry.get("address_family", []): + item["aggregate_address"] = {x["value"]: x for x in item.get("aggregate_address", [])} + item["networks"] = {x["network"]: x for x in item.get("networks", [])} + item["redistribute"] = { + (x.get("id"), x["protocol"]): x for x in item.get("redistribute", []) + } + + if "address_family" in entry: + entry["address_family"] = { + "address_family_" + x["afi"] + "_" + x["safi"] + "_vrf_" + x.get("vrf", ""): x + for x in entry.get("address_family", []) + } + + def _get_config(self): + return self._connection.get("show running-config router bgp") + + def _set_to_delete(self, haved, wantd): + afs_to_del = {} + h_addrs = haved.get("address_family", {}) + w_addrs = wantd.get("address_family", {}) + for af, h_addr in iteritems(h_addrs): + if af in w_addrs: + afs_to_del[af] = h_addr + return afs_to_del diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/bgp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/bgp_global.py new file mode 100644 index 00000000..69b752be --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_global/bgp_global.py @@ -0,0 +1,427 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_bgp_global config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_global import ( + Bgp_globalTemplate, +) + + +class Bgp_global(ResourceModule): + """ + The iosxr_bgp_global config class + """ + + def __init__(self, module): + super(Bgp_global, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="bgp_global", + tmplt=Bgp_globalTemplate(), + ) + self.parsers = [ + "router", + "bfd_multiplier", + "bfd_minimum_interval", + "bgp_auto_policy_soft_reset", + "bgp_as_path_loopcheck", + "bgp_cluster_id", + "bgp_default_local_preference", + "bgp_enforce_first_as_disable", + "bgp_fast_external_fallover_disable", + "bgp_install_diversion", + "bgp_max_neighbors", + "bgp_redistribute_internal", + "bgp_router_id", + "bgp_scan_time", + "bgp_unsafe_ebgp_policy", + "bgp_update_delay", + "bgp_bestpath_aigp", + "bgp_bestpath_as_path_ignore", + "bgp_bestpath_as_path_multipath_relax", + "bgp_bestpath_med_always", + "bgp_bestpath_med_confed", + "bgp_bestpath_med_missing_as_worst", + "bgp_bestpath_compare_routerid", + "bgp_bestpath_cost_community_ignore", + "bgp_bestpath_origin_as_use", + "bgp_bestpath_origin_as_allow", + "bgp_confederation_identifier", + "bgp_graceful_restart_set", + "bgp_graceful_restart_graceful_reset", + "bgp_graceful_restart_restart_time", + "bgp_graceful_restart_purge_time", + "bgp_graceful_restart_stalepath_time", + "bgp_log_message", + "bgp_log_neighbor_changes_detail", + "bgp_log_neighbor_changes_disable", + "bgp_multipath_as_path_ignore_onwards", + "bgp_origin_as_validation_disable", + "bgp_origin_as_validation_signal_ibgp", + "bgp_origin_as_validation_time_off", + "bgp_origin_as_validation_time", + "bgp_default_information_originate", + "bgp_default_metric", + "bgp_graceful_maintenance", + "ibgp_policy_out_enforce_modifications", + "mpls_activate_interface", + "mvpn", + "nsr_set", + "nsr_disable", + "socket_receive_buffer_size", + "socket_send_buffer_size", + "update_in_error_handling_basic_ebgp_disable", + "update_in_error_handling_basic_ibgp_disable", + "update_in_error_handling_extended_ebgp", + "update_in_error_handling_extended_ibgp", + "update_out_logging", + "update_limit", + "rpki_route_value", + "rd_auto", + "timers_keepalive", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + if self.state in ["merged", "replaced"]: + w_asn = self.want.get("as_number") + h_asn = self.have.get("as_number") + + if h_asn and w_asn != h_asn: + self._module.fail_json( + msg="BGP is already configured with ASN {0}. " + "Please remove it with state purged before " + "configuring new as_number".format(h_asn), + ) + for entry in self.want, self.have: + self._bgp_list_to_dict(entry) + + # if state is deleted, clean up global params + if self.state == "deleted": + if not self.want or (self.have.get("as_number") == self.want.get("as_number")): + self._compare( + want={"as_number": self.want.get("as_number")}, + have=self.have, + ) + elif self.state == "purged": + if not self.want or (self.have.get("as_number") == self.want.get("as_number")): + self.addcmd(self.have or {}, "router", True) + + else: + wantd = self.want + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(self.have, self.want) + + self._compare(want=wantd, have=self.have) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global network resource. + """ + + self.compare(parsers=self.parsers, want=want, have=have) + self._compare_rpki_server(want=want, have=self.have) + self._compare_confederation_peers(want=want, have=have) + self._compare_neighbors(want=want, have=self.have) + self._vrfs_compare(want=want, have=have) + if self.commands and "router bgp" not in self.commands[0]: + self.commands.insert( + 0, + self._tmplt.render( + {"as_number": want["as_number"]}, + "router", + False, + ), + ) + + def _compare_rpki_server(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global rpki servers resource. + """ + rpki_server_parsers = [ + "rpki_server_purge_time", + "rpki_server_refresh_time", + "rpki_server_refresh_time_off", + "rpki_server_response_time", + "rpki_server_response_time_off", + "rpki_server_shutdown", + "rpki_server_transport_ssh", + "rpki_server_transport_tcp", + ] + want = want.get("rpki", {}).get("servers", {}) + have = have.get("rpki", {}).get("servers", {}) + for name, entry in iteritems(want): + new_have = have.pop(name, {}) + begin = len(self.commands) + self.compare( + parsers=rpki_server_parsers, + want=entry, + have=new_have, + ) + rpki_server_name = entry.get("name") + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render( + {"name": rpki_server_name}, + "rpki_server_name", + False, + ), + ) + for name, entry in iteritems(have): + self.addcmd(entry, "rpki_server_name", True) + + def _compare_confederation_peers(self, want, have): + """Custom handling of confederation.peers option + :params want: the want BGP dictionary + :params have: the have BGP dictionary + """ + w_cpeers = want.get("bgp", {}).get("confederation", {}).get("peers", []) + h_cpeers = have.get("bgp", {}).get("confederation", {}).get("peers", []) + + if set(w_cpeers) != set(h_cpeers): + if self.state in ["replaced", "deleted"]: + # if there are peers already configured + # we need to remove those before we pass + # the new ones otherwise the device appends + # them to the existing ones + if h_cpeers: + self.addcmd(have, "bgp_confederation_peers", True) + if w_cpeers: + self.addcmd(want, "bgp_confederation_peers", False) + + def _compare_neighbors(self, want, have, vrf=None): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global neighbor resource. + """ + neighbor_parsers = [ + "advertisement_interval", + "bfd_fast_detect_disable", + "bfd_fast_detect_strict_mode", + "bfd_fast_detect_set", + "bfd_nbr_minimum_interval", + "bfd_nbr_multiplier", + "bmp_activate", + "dmz_link_bandwidth", + "dmz_link_bandwidth_inheritance_disable", + "neighbor_description", + "neighbor_cluster_id", + "dscp", + "ebgp_multihop_value", + "ebgp_multihop_mpls", + "ebgp_recv_extcommunity_dmz", + "ebgp_recv_extcommunity_dmz_set", + "ebgp_send_extcommunity_dmz", + "ebgp_send_extcommunity_dmz_set", + "ebgp_send_extcommunity_dmz_cumulatie", + "egress_engineering", + "egress_engineering_set", + "ignore_connected_check", + "ignore_connected_check_set", + "neighbor_enforce_first_as_disable", + "neighbor_graceful_restart_restart_time", + "neighbor_graceful_restart_stalepath_time", + "keychain", + "keychain_name", + "local_as_inheritance_disable", + "local_as", + "local", + "local_address", + "origin_as", + "remote_as", + "receive_buffer_size", + "send_buffer_size", + "session_open_mode", + "neighbor_shutdown", + "neighbor_shutdown_inheritance_disable", + "neighbor_tcp_mss", + "neighbor_tcp_mss_inheritance_disable", + "neighbor_timers_keepalive", + "update_source", + "neighbor_ttl_security_inheritance_disable", + "neighbor_ttl_security", + "neighbor_graceful_maintenance_set", + "neighbor_graceful_maintenance_activate", + "neighbor_graceful_maintenance_activate_inheritance_disable", + "neighbor_graceful_maintenance_as_prepends", + "neighbor_graceful_maintenance_local_preference_disable", + "neighbor_graceful_maintenance_local_preference", + "neighbor_graceful_maintenance_as_prepends_value", + "neighbor_capability_additional_paths_send", + "neighbor_capability_additional_paths_send_disable", + "neighbor_capability_additional_paths_rcv_disable", + "neighbor_capability_additional_paths_rcv", + "neighbor_capability_suppress_four_byte_AS", + "neighbor_capability_suppress_all", + "neighbor_capability_suppress_all_inheritance_disable", + "neighbor_log_message_in_value", + "neighbor_log_message_in_disable", + "neighbor_log_message_in_inheritance_disable", + "neighbor_log_message_out_value", + "neighbor_log_message_out_disable", + "neighbor_log_message_out_inheritance_disable", + "neighbor_update_in_filtering_attribute_filter_group", + "neighbor_update_in_filtering_logging_disable", + "neighbor_update_in_filtering_message_buffers", + ] + + want_nbr = want.get("neighbors", {}) + have_nbr = have.get("neighbors", {}) + for name, entry in iteritems(want_nbr): + have = have_nbr.pop(name, {}) + begin = len(self.commands) + self.compare(parsers=neighbor_parsers, want=entry, have=have) + neighbor_address = entry.get("neighbor_address", "") + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render( + {"neighbor_address": neighbor_address}, + "neighbor_address", + False, + ), + ) + for name, entry in iteritems(have_nbr): + if self._check_af("neighbor_address", name): + self._module.fail_json( + msg="Neighbor {0} has address-family configurations. " + "Please use the iosxr_bgp_neighbor_address_family module to remove those first.".format( + name, + ), + ) + else: + self.addcmd(entry, "neighbor_address", True) + + def _vrfs_compare(self, want, have): + """Custom handling of VRFs option + :params want: the want BGP dictionary + :params have: the have BGP dictionary + """ + wvrfs = want.get("vrfs", {}) + hvrfs = have.get("vrfs", {}) + for name, entry in iteritems(wvrfs): + begin = len(self.commands) + vrf_have = hvrfs.pop(name, {}) + self._compare_rpki_server(want=entry, have=vrf_have) + self._compare_neighbors(want=entry, have=vrf_have) + self.compare(parsers=self.parsers, want=entry, have=vrf_have) + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render( + {"vrf": entry.get("vrf")}, + "vrf", + False, + ), + ) + # cleanup remaining VRFs + # but do not negate it entirely + # instead remove only those attributes + # that this module manages + for name, entry in iteritems(hvrfs): + if self._check_af("vrf", name): + self._module.fail_json( + msg="VRF {0} has address-family configurations. " + "Please use the iosxr_bgp_address_family module to remove those first.".format( + name, + ), + ) + else: + self.addcmd(entry, "vrf", True) + + def _bgp_list_to_dict(self, entry): + """Convert list of items to dict of items + for efficient diff calculation. + :params entry: data dictionary + """ + + def _build_key(x): + """Build primary key for path_attribute + option. + :params x: path_attribute dictionary + :returns: primary key as tuple + """ + key_1 = "start_{0}".format(x.get("range", {}).get("start", "")) + key_2 = "end_{0}".format(x.get("range", {}).get("end", "")) + key_3 = "type_{0}".format(x.get("type", "")) + key_4 = x["action"] + + return (key_1, key_2, key_3, key_4) + + if "servers" in entry.get("rpki", {}): + entry["rpki"]["servers"] = { + x["name"]: x for x in entry.get("rpki", {}).get("servers", []) + } + if "neighbors" in entry: + entry["neighbors"] = {x["neighbor_address"]: x for x in entry.get("neighbors", [])} + + if "vrfs" in entry: + entry["vrfs"] = {x["vrf"]: x for x in entry.get("vrfs", [])} + for _k, vrf in iteritems(entry["vrfs"]): + self._bgp_list_to_dict(vrf) + + def _get_config(self): + return self._connection.get("show running-config router bgp") + + def _check_af(self, context, context_name): + af_present = False + if self._connection: + config_lines = self._get_config().splitlines() + index = [i + 1 for i, el in enumerate(config_lines) if context_name in el] + if index: + # had to do this to escape flake8 and black errors + ind = index[0] + for line in config_lines[ind:]: + if context in line: + break + if "address-family" in line: + af_present = True + break + return af_present diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/bgp_neighbor_address_family.py new file mode 100644 index 00000000..8f72127d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/bgp_neighbor_address_family/bgp_neighbor_address_family.py @@ -0,0 +1,245 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_bgp_neighbor_address_family config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_neighbor_address_family import ( + Bgp_neighbor_address_familyTemplate, +) + + +class Bgp_neighbor_address_family(ResourceModule): + """ + The iosxr_bgp_neighbor_address_family config class + """ + + def __init__(self, module): + super(Bgp_neighbor_address_family, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="bgp_neighbor_address_family", + tmplt=Bgp_neighbor_address_familyTemplate(), + ) + self.parsers = [ + "router", + "aigp", + "allowas_in", + "as_override", + "bestpath_origin_as_allow_invalid", + "capability_orf_prefix", + "default_originate", + "long_lived_graceful_restart_capable", + "long_lived_graceful_restart_stale_time", + "maximum_prefix", + "multipath", + "next_hop_self", + "next_hop_unchanged", + "optimal_route_reflection_group_name", + "origin_as", + "remove_private_AS", + "route_reflector_client", + "send_community_ebgp", + "send_community_gshut_ebgp", + "send_extended_community_ebgp", + "send_multicast_attributes", + "soft_reconfiguration", + "weight", + "site_of_origin", + "validation", + "route_policy.inbound", + "route_policy.outbound", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + + for entry in self.want, self.have: + self._bgp_list_to_dict(entry) + + wantd = self.want + haved = self.have + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(self.have, self.want) + + # if state is deleted, empty out wantd and set haved to elements to delete + if self.state == "deleted": + if wantd: + to_del = { + "neighbors": self._set_to_delete(haved, wantd), + "vrfs": {}, + } + + for k, hvrf in iteritems(haved.get("vrfs", {})): + wvrf = wantd.get("vrfs", {}).get(k, {}) + to_del["vrfs"][k] = { + "neighbors": self._set_to_delete(hvrf, wvrf), + "vrf": k, + } + haved.update(to_del) + + wantd = {"as_number": haved.get("as_number")} + + self._compare(want=wantd, have=haved) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global network resource. + """ + + self._compare_neighbors(want=want, have=have) + self._compare_vrf(want=want, have=have) + if self.commands and "router bgp" not in self.commands[0]: + self.commands.insert( + 0, + self._tmplt.render( + {"as_number": want["as_number"]}, + "router", + False, + ), + ) + + def _compare_neighbors(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Bgp_global neighbor resource. + """ + want_nbr = want.get("neighbors", {}) + have_nbr = have.get("neighbors", {}) + for name, entry in iteritems(want_nbr): + have = have_nbr.pop(name, {}) + begin = len(self.commands) + self._compare_af(want=entry, have=have) + if len(self.commands) != begin: + self.commands.insert(begin, "neighbor {0}".format(name)) + + # for deleted and overridden state + if self.state != "replaced": + for name, entry in iteritems(have_nbr): + begin = len(self.commands) + self._compare_af(want={}, have=entry) + if len(self.commands) != begin: + self.commands.insert(begin, "neighbor {0}".format(name)) + + def _compare_af(self, want, have): + """Custom handling of afs option + :params want: the want BGP dictionary + :params have: the have BGP dictionary + """ + wafs = want.get("address_family", {}) + hafs = have.get("address_family", {}) + for name, entry in iteritems(wafs): + begin = len(self.commands) + af_have = hafs.pop(name, {}) + self.compare(parsers=self.parsers, want=entry, have=af_have) + if len(self.commands) != begin or (not af_have and entry): + self.commands.insert( + begin, + self._tmplt.render( + {"afi": entry.get("afi"), "safi": entry.get("safi")}, + "address_family", + False, + ), + ) + + for name, entry in iteritems(hafs): + self.addcmd( + {"afi": entry.get("afi"), "safi": entry.get("safi")}, + "address_family", + True, + ) + + def _compare_vrf(self, want, have): + """Custom handling of VRFs option + :params want: the want BGP dictionary + :params have: the have BGP dictionary + """ + wvrfs = want.get("vrfs", {}) + hvrfs = have.get("vrfs", {}) + for name, entry in iteritems(wvrfs): + begin = len(self.commands) + vrf_have = hvrfs.pop(name, {}) + self._compare_neighbors(want=entry, have=vrf_have) + if len(self.commands) != begin: + self.commands.insert(begin, "vrf {0}".format(name)) + # for deleted and replaced state + for name, entry in iteritems(hvrfs): + begin = len(self.commands) + self._compare_neighbors(want={}, have=entry) + if len(self.commands) != begin: + self.commands.insert(begin, "vrf {0}".format(name)) + + def _bgp_list_to_dict(self, data): + if "neighbors" in data: + for nbr in data["neighbors"]: + if "address_family" in nbr: + nbr["address_family"] = { + (x["afi"], x.get("safi")): x for x in nbr["address_family"] + } + data["neighbors"] = {x["neighbor_address"]: x for x in data["neighbors"]} + + if "vrfs" in data: + for vrf in data["vrfs"]: + self._bgp_list_to_dict(vrf) + data["vrfs"] = {x["vrf"]: x for x in data["vrfs"]} + + def _set_to_delete(self, haved, wantd): + neighbors = {} + h_nbrs = haved.get("neighbors", {}) + w_nbrs = wantd.get("neighbors", {}) + + for k, h_nbr in iteritems(h_nbrs): + w_nbr = w_nbrs.pop(k, {}) + if w_nbr: + neighbors[k] = h_nbr + afs_to_del = {} + h_addrs = h_nbr.get("address_family", {}) + w_addrs = w_nbr.get("address_family", {}) + for af, h_addr in iteritems(h_addrs): + if af in w_addrs: + afs_to_del[af] = h_addr + neighbors[k]["address_family"] = afs_to_del + + return neighbors diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/hostname.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/hostname.py new file mode 100644 index 00000000..deb6ea05 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/hostname/hostname.py @@ -0,0 +1,75 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_hostname config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.hostname import ( + HostnameTemplate, +) + + +class Hostname(ResourceModule): + """ + The iosxr_hostname config class + """ + + def __init__(self, module): + super(Hostname, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="hostname", + tmplt=HostnameTemplate(), + ) + self.parsers = ["hostname"] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self.want + haved = self.have + + if self.state == "deleted": + wantd = {} + + self._compare(want=wantd, have=haved) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Hostname network resource. + """ + self.compare(parsers=self.parsers, want=want, have=have) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/interfaces.py new file mode 100644 index 00000000..2a0c1885 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/interfaces/interfaces.py @@ -0,0 +1,311 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + add_command_to_config_list, + dict_to_set, + filter_dict_having_none_value, + get_interface_type, + normalize_interface, + remove_command_from_config_list, + remove_duplicate_interface, +) + + +class Interfaces(ConfigBase): + """ + The iosxr_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["interfaces"] + + params = ("description", "mtu", "speed", "duplex") + + def __init__(self, module): + super(Interfaces, self).__init__(module) + + def get_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + :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, + ) + interfaces_facts = facts["ansible_network_resources"].get("interfaces") + if not interfaces_facts: + return [] + return interfaces_facts + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_interfaces_facts = self.get_interfaces_facts() + else: + existing_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_interfaces_facts = self.get_interfaces_facts() + + 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_interfaces_facts(data=running_config) + + if self.state in self.ACTION_STATES: + result["before"] = existing_interfaces_facts + if result["changed"]: + result["after"] = changed_interfaces_facts + + elif self.state == "gathered": + result["gathered"] = changed_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_interfaces_facts + resp = self.set_state(want, have) + + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + if self.state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + self.state, + ), + ) + + if self.state == "overridden": + commands = self._state_overridden(want, have) + elif self.state == "deleted": + commands = self._state_deleted(want, have) + elif self.state in ("merged", "rendered"): + commands = self._state_merged(want, have) + elif self.state == "replaced": + commands = self._state_replaced(want, have) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for interface in want: + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + continue + have_dict = filter_dict_having_none_value(interface, each) + want = dict() + commands.extend(self._clear_config(want, have_dict)) + commands.extend(self._set_config(interface, each)) + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_overridden(self, want, have): + """The command generator when state is overridden + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for each in have: + for interface in want: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + # We didn't find a matching desired state, which means we can + # pretend we received an empty desired state. + interface = dict(name=each["name"]) + commands.extend(self._clear_config(interface, each)) + continue + have_dict = filter_dict_having_none_value(interface, each) + want = dict() + commands.extend(self._clear_config(want, have_dict)) + commands.extend(self._set_config(interface, each)) + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + flag = 0 + for interface in want: + if self.state == "rendered": + commands.extend(self._set_config(interface, dict())) + else: + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + flag = 1 + break + if flag == 1: + commands.extend(self._set_config(interface, each)) + else: + commands.extend(self._set_config(interface, dict())) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if want: + for interface in want: + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + continue + interface = dict(name=interface["name"]) + commands.extend(self._clear_config(interface, each)) + else: + for each in have: + want = dict() + commands.extend(self._clear_config(want, each)) + + return commands + + def _set_config(self, want, have): + # Set the interface config based on the want and have config + commands = [] + want["name"] = normalize_interface(want["name"]) + interface = "interface " + want["name"] + # Get the diff b/w want and have + want_dict = dict_to_set(want) + have_dict = dict_to_set(have) + diff = want_dict - have_dict + + if diff: + diff = dict(diff) + for item in self.params: + if diff.get(item): + cmd = item + " " + str(want.get(item)) + add_command_to_config_list(interface, cmd, commands) + if diff.get("enabled"): + add_command_to_config_list(interface, "no shutdown", commands) + elif diff.get("enabled") is False: + add_command_to_config_list(interface, "shutdown", commands) + + return commands + + def _clear_config(self, want, have): + # Delete the interface config based on the want and have config + commands = [] + + if want.get("name"): + interface_type = get_interface_type(want["name"]) + interface = "interface " + want["name"] + else: + interface_type = get_interface_type(have["name"]) + interface = "interface " + have["name"] + + if have.get("description") and want.get("description") != have.get( + "description", + ): + remove_command_from_config_list(interface, "description", commands) + if not have.get("enabled") and want.get("enabled") != have.get( + "enabled", + ): + # if enable is False set enable as True which is the default behavior + remove_command_from_config_list(interface, "shutdown", commands) + + if interface_type.lower() == "gigabitethernet": + if ( + have.get("speed") + and have.get("speed") != "auto" + and want.get("speed") != have.get("speed") + ): + remove_command_from_config_list(interface, "speed", commands) + if ( + have.get("duplex") + and have.get("duplex") != "auto" + and want.get("duplex") != have.get("duplex") + ): + remove_command_from_config_list(interface, "duplex", commands) + if have.get("mtu") and want.get("mtu") != have.get("mtu"): + remove_command_from_config_list(interface, "mtu", commands) + + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py new file mode 100644 index 00000000..c571d3fa --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l2_interfaces/l2_interfaces.py @@ -0,0 +1,410 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_l2_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_empties, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import get_os_version +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + Version, + add_command_to_config_list, + dict_diff, + filter_dict_having_none_value, + normalize_interface, + remove_command_from_config_list, + remove_duplicate_interface, +) + + +class L2_Interfaces(ConfigBase): + """ + The iosxr_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["l2_interfaces"] + + def get_l2_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + :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, + ) + l2_interfaces_facts = facts["ansible_network_resources"].get( + "l2_interfaces", + ) + if not l2_interfaces_facts: + return [] + return l2_interfaces_facts + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_l2_interfaces_facts = self.get_l2_interfaces_facts() + else: + existing_l2_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_l2_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_l2_interfaces_facts = self.get_l2_interfaces_facts() + + 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_l2_interfaces_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_l2_interfaces_facts + if result["changed"]: + result["after"] = changed_l2_interfaces_facts + + elif self.state == "gathered": + result["gathered"] = changed_l2_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_l2_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_l2_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + if self.state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + self.state, + ), + ) + + if self.state == "overridden": + commands = self._state_overridden(want, have, self._module) + elif self.state == "deleted": + commands = self._state_deleted(want, have) + elif self.state in ("merged", "rendered"): + commands = self._state_merged(want, have, self._module) + elif self.state == "replaced": + commands = self._state_replaced(want, have, self._module) + + return commands + + def _state_replaced(self, want, have, module): + """The command generator when state is replaced + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + commands.extend(self._set_config(interface, {}, module)) + continue + interface = remove_empties(interface) + have_dict = filter_dict_having_none_value(interface, each) + commands.extend(self._clear_config(dict(), have_dict)) + commands.extend(self._set_config(interface, each, module)) + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_overridden(self, want, have, module): + """The command generator when state is overridden + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + not_in_have = set() + in_have = set() + for each in have: + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + if each["name"] == interface["name"]: + in_have.add(interface["name"]) + break + if interface["name"] != each["name"]: + not_in_have.add(interface["name"]) + else: + # We didn't find a matching desired state, which means we can + # pretend we received an empty desired state. + interface = dict(name=each["name"]) + commands.extend(self._clear_config(interface, each)) + continue + interface = remove_empties(interface) + have_dict = filter_dict_having_none_value(interface, each) + commands.extend(self._clear_config(dict(), have_dict)) + commands.extend(self._set_config(interface, each, module)) + # Add the want interface that's not already configured in have interface + for each in not_in_have - in_have: + for every in want: + interface = "interface {0}".format(every["name"]) + if each and interface not in commands: + commands.extend(self._set_config(every, {}, module)) + + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_merged(self, want, have, module): + """The command generator when state is merged + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + interface = remove_empties(interface) + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + commands.extend(self._set_config(interface, {}, module)) + continue + commands.extend(self._set_config(interface, each, module)) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if want: + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + continue + interface = dict(name=interface["name"]) + commands.extend(self._clear_config(interface, each)) + else: + for each in have: + want = dict() + commands.extend(self._clear_config(want, each)) + + return commands + + def _set_config(self, want, have, module): + # Set the interface config based on the want and have config + commands = [] + interface = "interface " + want["name"] + l2_protocol_bool = False + # Get the diff b/w want and have + diff = dict_diff(have, want) + if diff: + # For merging with already configured l2protocol + if have.get("l2protocol") and len(have.get("l2protocol")) > 1: + l2_protocol_diff = [] + for each in want.get("l2protocol"): + for every in have.get("l2protocol"): + if every == each: + break + if each not in have.get("l2protocol"): + l2_protocol_diff.append(each) + l2_protocol_bool = True + l2protocol = tuple(l2_protocol_diff) + else: + l2protocol = {} + + wants_native = diff.get("native_vlan") + l2transport = diff.get("l2transport") + q_vlan = diff.get("q_vlan") + encapsulation = diff.get("encapsulation") + propagate = diff.get("propagate") + if l2_protocol_bool is False: + l2protocol = diff.get("l2protocol") + + os_version = get_os_version(self._module) + if os_version and Version(os_version) < Version("7.0.0"): + if wants_native: + cmd = "dot1q native vlan {0}".format(wants_native) + add_command_to_config_list(interface, cmd, commands) + + if l2transport or l2protocol: + for each in l2protocol: + each = dict(each) + if isinstance(each, dict) and list(each.keys())[0] != "cpsv": + cmd = "l2transport l2protocol {0} {1}".format( + list(each.keys())[0], + list(each.values())[0], + ) + add_command_to_config_list(interface, cmd, commands) + + if q_vlan and "." in interface: + q_vlans = " ".join(map(str, want.get("q_vlan"))) + if q_vlans != have.get("q_vlan"): + cmd = "dot1q vlan {0}".format(q_vlans) + add_command_to_config_list(interface, cmd, commands) + else: + if l2transport or l2protocol: + for each in l2protocol: + each = dict(each) + if isinstance(each, dict) and "cpsv" in list( + each.keys(), + ): + cmd = "l2transport l2protocol {0} {1}".format( + "cpsv", + each.get("cpsv"), + ) + add_command_to_config_list( + interface, + cmd, + commands, + ) + break + if encapsulation: + encapsulation = dict(encapsulation) + if encapsulation.get("dot1q"): + if encapsulation.get("second_dot1q"): + cmd = "encapsulation dot1q {0} second-dot1q {1}".format( + encapsulation.get("dot1q"), + encapsulation.get("second_dot1q"), + ) + else: + cmd = "encapsulation dot1q {0}".format( + encapsulation.get("dot1q"), + ) + add_command_to_config_list(interface, cmd, commands) + + if l2transport or l2protocol: + if propagate and not have.get("propagate"): + cmd = "l2transport propagate remote-status" + add_command_to_config_list(interface, cmd, commands) + elif want.get("l2transport") is False and ( + want.get("l2protocol") or want.get("propagate") + ): + module.fail_json( + msg="L2transport L2protocol or Propagate can only be configured when " + "L2transport set to True!", + ) + + return commands + + def _clear_config(self, want, have): + # Delete the interface config based on the want and have config + commands = [] + + if want.get("name"): + interface = "interface " + want["name"] + else: + interface = "interface " + have["name"] + os_version = get_os_version(self._module) + if os_version and Version(os_version) < Version("7.0.0"): + if have.get("native_vlan"): + remove_command_from_config_list( + interface, + "dot1q native vlan", + commands, + ) + + if have.get("q_vlan"): + remove_command_from_config_list( + interface, + "encapsulation dot1q", + commands, + ) + else: + if have.get("encapsulation"): + remove_command_from_config_list( + interface, + "encapsulation dot1q", + commands, + ) + + if have.get("l2protocol") and ( + want.get("l2protocol") is None or want.get("propagate") is None + ): + if "no l2transport" not in commands: + remove_command_from_config_list( + interface, + "l2transport", + commands, + ) + elif have.get("l2transport") and have.get("l2transport") != want.get( + "l2transport", + ): + if "no l2transport" not in commands: + remove_command_from_config_list( + interface, + "l2transport", + commands, + ) + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py new file mode 100644 index 00000000..98b7c596 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/l3_interfaces/l3_interfaces.py @@ -0,0 +1,382 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_l3_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + add_command_to_config_list, + dict_to_set, + filter_dict_having_none_value, + normalize_interface, + remove_command_from_config_list, + remove_duplicate_interface, + validate_ipv6, + validate_n_expand_ipv4, +) + + +class L3_Interfaces(ConfigBase): + """ + The iosxr_l3_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["l3_interfaces"] + + def get_l3_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + :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, + ) + l3_interfaces_facts = facts["ansible_network_resources"].get( + "l3_interfaces", + ) + if not l3_interfaces_facts: + return [] + return l3_interfaces_facts + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_l3_interfaces_facts = self.get_l3_interfaces_facts() + else: + existing_l3_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_l3_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_l3_interfaces_facts = self.get_l3_interfaces_facts() + + 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_l3_interfaces_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_l3_interfaces_facts + if result["changed"]: + result["after"] = changed_l3_interfaces_facts + + elif self.state == "gathered": + result["gathered"] = changed_l3_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_l3_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_l3_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + if self.state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + self.state, + ), + ) + + if self.state == "overridden": + commands = self._state_overridden(want, have, self._module) + elif self.state == "deleted": + commands = self._state_deleted(want, have) + elif self.state in ("merged", "rendered"): + commands = self._state_merged(want, have, self._module) + elif self.state == "replaced": + commands = self._state_replaced(want, have, self._module) + + return commands + + def _state_replaced(self, want, have, module): + """The command generator when state is replaced + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + for each in have: + if each["name"] == interface["name"]: + break + else: + commands.extend(self._set_config(interface, dict(), module)) + continue + have_dict = filter_dict_having_none_value(interface, each) + commands.extend(self._clear_config(dict(), have_dict)) + commands.extend(self._set_config(interface, each, module)) + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_overridden(self, want, have, module): + """The command generator when state is overridden + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + not_in_have = set() + in_have = set() + + for each in have: + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + if each["name"] == interface["name"]: + in_have.add(interface["name"]) + break + if interface["name"] != each["name"]: + not_in_have.add(interface["name"]) + else: + # We didn't find a matching desired state, which means we can + # pretend we received an empty desired state. + interface = dict(name=each["name"]) + kwargs = {"want": interface, "have": each} + commands.extend(self._clear_config(**kwargs)) + continue + have_dict = filter_dict_having_none_value(interface, each) + commands.extend(self._clear_config(dict(), have_dict)) + commands.extend(self._set_config(interface, each, module)) + # Add the want interface that's not already configured in have interface + for each in not_in_have - in_have: + for every in want: + interface = "interface {0}".format(every["name"]) + if each and interface not in commands: + commands.extend(self._set_config(every, {}, module)) + # Remove the duplicate interface call + commands = remove_duplicate_interface(commands) + + return commands + + def _state_merged(self, want, have, module): + """The command generator when state is merged + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + if self.state == "rendered": + commands.extend(self._set_config(interface, dict(), module)) + else: + for each in have: + if each["name"] == interface["name"]: + break + else: + commands.extend( + self._set_config(interface, dict(), module), + ) + continue + commands.extend(self._set_config(interface, each, module)) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if want: + for interface in want: + interface["name"] = normalize_interface(interface["name"]) + for each in have: + if each["name"] == interface["name"] or interface["name"] in each["name"]: + break + else: + continue + interface = dict(name=interface["name"]) + commands.extend(self._clear_config(interface, each)) + else: + for each in have: + want = dict() + commands.extend(self._clear_config(want, each)) + + return commands + + def verify_diff_again(self, want, have): + """ + Verify the IPV4 difference again as sometimes due to + change in order of set, set difference may result into change, + when there's actually no difference between want and have + :param want: want_dict IPV4 + :param have: have_dict IPV4 + :return: diff + """ + diff = False + for each in want: + each_want = dict(each) + for every in have: + every_have = dict(every) + + if each_want.get("address") == every_have.get("address"): + if len(each_want.keys()) == len(every_have.keys()) and ( + each_want.get("secondary") == every_have.get("secondary") + ): + diff = False + break + if not each_want.get("secondary") and not every_have.get( + "secondary", + ): + diff = False + break + + diff = True + else: + diff = True + if diff: + break + + return diff + + def _set_config(self, want, have, module): + # Set the interface config based on the want and have config + commands = [] + interface = "interface " + want["name"] + + # To handle L3 IPV4 configuration + if want.get("ipv4"): + for each in want.get("ipv4"): + if each.get("address") != "dhcp": + ip_addr_want = validate_n_expand_ipv4(module, each) + each["address"] = ip_addr_want + + # Get the diff b/w want and have + want_dict = dict_to_set(want) + have_dict = dict_to_set(have) + + # To handle L3 IPV4 configuration + want_ipv4 = dict(want_dict).get("ipv4") + have_ipv4 = dict(have_dict).get("ipv4") + if want_ipv4: + if have_ipv4: + diff_ipv4 = set(want_ipv4) - set(dict(have_dict).get("ipv4")) + if diff_ipv4: + diff_ipv4 = diff_ipv4 if self.verify_diff_again(want_ipv4, have_ipv4) else () + else: + diff_ipv4 = set(want_ipv4) + for each in diff_ipv4: + ipv4_dict = dict(each) + if ipv4_dict.get("address") != "dhcp": + cmd = "ipv4 address {0}".format(ipv4_dict["address"]) + if ipv4_dict.get("secondary"): + cmd += " secondary" + add_command_to_config_list(interface, cmd, commands) + + # To handle L3 IPV6 configuration + want_ipv6 = dict(want_dict).get("ipv6") + have_ipv6 = dict(have_dict).get("ipv6") + if want_ipv6: + if have_ipv6: + diff_ipv6 = set(want_ipv6) - set(have_ipv6) + else: + diff_ipv6 = set(want_ipv6) + for each in diff_ipv6: + ipv6_dict = dict(each) + validate_ipv6(ipv6_dict.get("address"), module) + cmd = "ipv6 address {0}".format(ipv6_dict.get("address")) + add_command_to_config_list(interface, cmd, commands) + + return commands + + def _clear_config(self, want, have): + # Delete the interface config based on the want and have config + count = 0 + commands = [] + if want.get("name"): + interface = "interface " + want["name"] + else: + interface = "interface " + have["name"] + + if have.get("ipv4") and want.get("ipv4"): + for each in have.get("ipv4"): + if each.get("secondary") and not (want.get("ipv4")[count].get("secondary")): + cmd = "ipv4 address {0} secondary".format( + each.get("address"), + ) + remove_command_from_config_list(interface, cmd, commands) + count += 1 + if have.get("ipv4") and not (want.get("ipv4")): + remove_command_from_config_list( + interface, + "ipv4 address", + commands, + ) + if have.get("ipv6") and not (want.get("ipv6")): + remove_command_from_config_list( + interface, + "ipv6 address", + commands, + ) + + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/lacp.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/lacp.py new file mode 100644 index 00000000..8a6744e5 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp/lacp.py @@ -0,0 +1,210 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_lacp class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + remove_empties, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_dict, +) + + +class Lacp(ConfigBase): + """ + The iosxr_lacp class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["lacp"] + + def __init__(self, module): + super(Lacp, self).__init__(module) + + def get_lacp_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + lacp_facts = facts["ansible_network_resources"].get("lacp") + if not lacp_facts: + return {} + return lacp_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_lacp_facts = self.get_lacp_facts() + else: + existing_lacp_facts = {} + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lacp_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lacp_facts = self.get_lacp_facts() + + 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_lacp_facts(data=running_config) + + if self.state in self.ACTION_STATES: + result["before"] = existing_lacp_facts + if result["changed"]: + result["after"] = changed_lacp_facts + + elif self.state == "gathered": + result["gathered"] = changed_lacp_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_lacp_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params.get("config") + if not want: + want = {} + have = existing_lacp_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + if self.state in ("merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + self.state, + ), + ) + + if self.state == "deleted": + commands = self._state_deleted(want, have) + elif self.state in ("merged", "rendered"): + commands = self._state_merged(want, have) + elif self.state == "replaced": + commands = self._state_replaced(want, have) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + commands.extend(self._state_deleted(want, have)) + + commands.extend(self._state_merged(want, have)) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + + updates = dict_diff(have, want) + if self.state == "rendered": + updates = want + if updates: + for key, value in iteritems( + flatten_dict(remove_empties(updates["system"])), + ): + commands.append( + "lacp system {0} {1}".format( + key.replace("address", "mac"), + value, + ), + ) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + for x in [ + k for k in have.get("system", {}) if k not in remove_empties(want.get("system", {})) + ]: + commands.append("no lacp system {0}".format(x)) + + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py new file mode 100644 index 00000000..a438726f --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lacp_interfaces/lacp_interfaces.py @@ -0,0 +1,309 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_lacp_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + remove_empties, + search_obj_in_list, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + dict_delete, + flatten_dict, + pad_commands, +) + + +class Lacp_interfaces(ConfigBase): + """ + The iosxr_lacp_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["lacp_interfaces"] + + def __init__(self, module): + super(Lacp_interfaces, self).__init__(module) + + def get_lacp_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + lacp_interfaces_facts = facts["ansible_network_resources"].get( + "lacp_interfaces", + ) + if not lacp_interfaces_facts: + return [] + return lacp_interfaces_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + commands = list() + warnings = list() + + if self.state in self.ACTION_STATES: + existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts() + else: + existing_lacp_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lacp_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts() + + 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_lacp_interfaces_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_lacp_interfaces_facts + if result["changed"]: + result["after"] = changed_lacp_interfaces_facts + elif self.state == "gathered": + result["gathered"] = changed_lacp_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_lacp_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_lacp_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + state = self._module.params["state"] + + if state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "overridden": + commands.extend(Lacp_interfaces._state_overridden(want, have)) + + elif state == "deleted": + if not want: + for intf in have: + commands.extend( + Lacp_interfaces._state_deleted( + {"name": intf["name"]}, + intf, + ), + ) + else: + for item in want: + obj_in_have = search_obj_in_list(item["name"], have) + commands.extend( + Lacp_interfaces._state_deleted(item, obj_in_have), + ) + + else: + for item in want: + name = item["name"] + obj_in_have = search_obj_in_list(name, have) + + if state in ("merged", "rendered"): + commands.extend( + Lacp_interfaces._state_merged(item, obj_in_have), + ) + + elif state == "replaced": + commands.extend( + Lacp_interfaces._state_replaced(item, obj_in_have), + ) + + return commands + + @staticmethod + def _state_replaced(want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + replaced_commands = [] + merged_commands = [] + + if have: + replaced_commands = Lacp_interfaces._state_deleted(want, have) + + merged_commands = Lacp_interfaces._state_merged(want, have) + + if merged_commands and replaced_commands: + del merged_commands[0] + + commands.extend(replaced_commands) + commands.extend(merged_commands) + + return commands + + @staticmethod + def _state_overridden(want, have): + """The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + for intf in have: + intf_in_want = search_obj_in_list(intf["name"], want) + if not intf_in_want: + commands.extend( + Lacp_interfaces._state_deleted( + {"name": intf["name"]}, + intf, + ), + ) + + for intf in want: + intf_in_have = search_obj_in_list(intf["name"], have) + commands.extend( + Lacp_interfaces._state_replaced(intf, intf_in_have), + ) + + return commands + + @staticmethod + def _state_merged(want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + + if not have: + have = {"name": want["name"]} + + for key, value in iteritems( + flatten_dict(remove_empties(dict_diff(have, want))), + ): + commands.append(Lacp_interfaces._compute_commands(key, value)) + + if commands: + pad_commands(commands, want["name"]) + + return commands + + @staticmethod + def _state_deleted(want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + for key, value in iteritems( + flatten_dict(dict_delete(have, remove_empties(want))), + ): + commands.append( + Lacp_interfaces._compute_commands(key, value, remove=True), + ) + + if commands: + pad_commands(commands, have["name"]) + + return commands + + @staticmethod + def _compute_commands(key, value, remove=False): + if key == "churn_logging": + cmd = "lacp churn logging {0}".format(value) + + elif key == "collector_max_delay": + cmd = "lacp collector-max-delay {0}".format(value) + + elif key == "period": + cmd = "lacp period {0}".format(value) + + elif key == "switchover_suppress_flaps": + cmd = "lacp switchover suppress-flaps {0}".format(value) + + elif key == "mac": + cmd = "lacp system mac {0}".format(value) + + elif key == "priority": + cmd = "lacp system priority {0}".format(value) + + if remove: + cmd = "no " + cmd + + return cmd diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..69422604 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lag_interfaces/lag_interfaces.py @@ -0,0 +1,446 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_lag_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + param_list_to_dict, + remove_empties, + search_obj_in_list, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import get_os_version +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + Version, + dict_delete, + diff_list_of_dicts, + flatten_dict, + normalize_interface, + pad_commands, +) + + +class Lag_interfaces(ConfigBase): + """ + The iosxr_lag_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["lag_interfaces"] + + def __init__(self, module): + super(Lag_interfaces, self).__init__(module) + + def get_lag_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + lag_interfaces_facts = facts["ansible_network_resources"].get( + "lag_interfaces", + ) + if not lag_interfaces_facts: + return [] + return lag_interfaces_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + if self.state in self.ACTION_STATES: + existing_lag_interfaces_facts = self.get_lag_interfaces_facts() + else: + existing_lag_interfaces_facts = {} + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lag_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lag_interfaces_facts = self.get_lag_interfaces_facts() + + 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_lag_interfaces_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_lag_interfaces_facts + if result["changed"]: + result["after"] = changed_lag_interfaces_facts + + elif self.state == "gathered": + result["gathered"] = changed_lag_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_lag_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + if want: + for item in want: + item["name"] = normalize_interface(item["name"]) + if "members" in want and want["members"]: + for item in want["members"]: + item.update( + { + "member": normalize_interface(item["member"]), + "mode": item["mode"], + }, + ) + have = existing_lag_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + state = self._module.params["state"] + commands = [] + + if self.state in ("merged", "replaced", "overridden", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "overridden": + commands.extend(self._state_overridden(want, have)) + + elif state == "deleted": + commands.extend(self._state_deleted(want, have)) + + else: + # Instead of passing entire want and have + # list of dictionaries to the respective + # _state_* methods we are passing the want + # and have dictionaries per interface + for item in want: + name = item["name"] + obj_in_have = search_obj_in_list(name, have) + + if state in ("merged", "rendered"): + commands.extend(self._state_merged(item, obj_in_have)) + + elif state == "replaced": + commands.extend(self._state_replaced(item, obj_in_have)) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + if have: + commands.extend(self._render_bundle_del_commands(want, have)) + commands.extend(self._render_bundle_updates(want, have)) + + if commands or have == {}: + pad_commands(commands, want["name"]) + + if have: + commands.extend(self._render_interface_del_commands(want, have)) + commands.extend(self._render_interface_updates(want, have)) + + return commands + + def _state_overridden(self, want, have): + """The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + for have_intf in have: + intf_in_want = search_obj_in_list(have_intf["name"], want) + if not intf_in_want: + commands.extend(self._purge_attribs(have_intf)) + + for intf in want: + intf_in_have = search_obj_in_list(intf["name"], have) + commands.extend(self._state_replaced(intf, intf_in_have)) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + commands.extend(self._render_bundle_updates(want, have)) + + if commands or have == {}: + pad_commands(commands, want["name"]) + + commands.extend(self._render_interface_updates(want, have)) + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + if not want: + for item in have: + commands.extend(self._purge_attribs(intf=item)) + else: + for item in want: + name = item["name"] + obj_in_have = search_obj_in_list(name, have) + if not obj_in_have: + self._module.fail_json( + msg=("interface {0} does not exist".format(name)), + ) + commands.extend(self._purge_attribs(intf=obj_in_have)) + + return commands + + def _render_bundle_updates(self, want, have): + """The command generator for updates to bundles + :rtype: A list + :returns: the commands necessary to update bundles + """ + commands = [] + if not have: + have = {"name": want["name"]} + + want_copy = deepcopy(want) + have_copy = deepcopy(have) + + want_copy.pop("members", []) + have_copy.pop("members", []) + + bundle_updates = dict_diff(have_copy, want_copy) + + if bundle_updates: + for key, value in iteritems( + flatten_dict(remove_empties(bundle_updates)), + ): + commands.append(self._compute_commands(key=key, value=value)) + + return commands + + def _render_interface_updates(self, want, have): + """The command generator for updates to member + interfaces + :rtype: A list + :returns: the commands necessary to update member + interfaces + """ + commands = [] + + if not have: + have = {"name": want["name"]} + + member_diff = diff_list_of_dicts( + want["members"], + have.get("members", []), + ) + + for diff in member_diff: + diff_cmd = [] + bundle_cmd = "bundle id {0}".format( + want["name"].split("Bundle-Ether")[1], + ) + if diff.get("mode"): + bundle_cmd += " mode {0}".format(diff.get("mode")) + diff_cmd.append(bundle_cmd) + pad_commands(diff_cmd, diff["member"]) + commands.extend(diff_cmd) + + return commands + + def _render_bundle_del_commands(self, want, have): + """The command generator for delete commands + w.r.t bundles + :rtype: A list + :returns: the commands necessary to update member + interfaces + """ + commands = [] + if not want: + want = {"name": have["name"]} + + want_copy = deepcopy(want) + have_copy = deepcopy(have) + want_copy.pop("members", []) + have_copy.pop("members", []) + + to_delete = dict_delete(have_copy, remove_empties(want_copy)) + if to_delete: + for key, value in iteritems( + flatten_dict(remove_empties(to_delete)), + ): + commands.append( + self._compute_commands(key=key, value=value, remove=True), + ) + + return commands + + def _render_interface_del_commands(self, want, have): + """The command generator for delete commands + w.r.t member interfaces + :rtype: A list + :returns: the commands necessary to update member + interfaces + """ + commands = [] + if not want: + want = {} + have_members = have.get("members") + + if have_members: + have_members = param_list_to_dict( + deepcopy(have_members), + unique_key="member", + ) + want_members = param_list_to_dict( + deepcopy(want).get("members", []), + unique_key="member", + ) + + for key in have_members: + if key not in want_members: + member_cmd = ["no bundle id"] + pad_commands(member_cmd, key) + commands.extend(member_cmd) + + return commands + + def _purge_attribs(self, intf): + """The command generator for purging attributes + :rtype: A list + :returns: the commands necessary to purge attributes + """ + commands = [] + have_copy = deepcopy(intf) + members = have_copy.pop("members", []) + + to_delete = dict_delete( + have_copy, + remove_empties({"name": have_copy["name"]}), + ) + if to_delete: + for key, value in iteritems( + flatten_dict(remove_empties(to_delete)), + ): + commands.append( + self._compute_commands(key=key, value=value, remove=True), + ) + + if commands: + pad_commands(commands, intf["name"]) + + if members: + members = param_list_to_dict( + deepcopy(members), + unique_key="member", + ) + for key in members: + member_cmd = ["no bundle id"] + pad_commands(member_cmd, key) + commands.extend(member_cmd) + + return commands + + def _compute_commands(self, key, value, remove=False): + """The method generates LAG commands based on the + key, value passed. When remove is set to True, + the command is negated. + :rtype: str + :returns: a command based on the `key`, `value` pair + passed and the value of `remove` + """ + if key == "mode": + cmd = "lacp mode {0}".format(value) + + elif key == "load_balancing_hash": + os_version = get_os_version(self._module) + if os_version and Version(os_version) < Version("7.0.0"): + cmd = "bundle load-balancing hash {0}".format(value) + + elif key == "max_active": + cmd = "bundle maximum-active links {0}".format(value) + + elif key == "min_active": + cmd = "bundle minimum-active links {0}".format(value) + + if remove: + cmd = "no {0}".format(cmd) + + return cmd diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/lldp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/lldp_global.py new file mode 100644 index 00000000..e4fda3c7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_global/lldp_global.py @@ -0,0 +1,223 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_lldp_global class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + remove_empties, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + dict_delete, + flatten_dict, +) + + +class Lldp_global(ConfigBase): + """ + The iosxr_lldp class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["lldp_global"] + + def __init__(self, module): + super(Lldp_global, self).__init__(module) + + def get_lldp_global_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + lldp_facts = facts["ansible_network_resources"].get("lldp_global") + if not lldp_facts: + return {} + return lldp_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + if self.state in self.ACTION_STATES: + existing_lldp_global_facts = self.get_lldp_global_facts() + else: + existing_lldp_global_facts = {} + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lldp_global_facts)) + + if commands and self.state in self.ACTION_STATES: + + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lldp_global_facts = self.get_lldp_global_facts() + + 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_lldp_global_facts(data=running_config) + + if self.state in self.ACTION_STATES: + result["before"] = existing_lldp_global_facts + if result["changed"]: + result["after"] = changed_lldp_global_facts + elif self.state == "gathered": + result["gathered"] = changed_lldp_global_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_lldp_global_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + if not want and self._module.params["state"] == "deleted": + want = {} + have = existing_lldp_global_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + state = self._module.params["state"] + if state in ("merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "deleted": + commands = self._state_deleted(want, have) + elif state in ("merged", "rendered"): + commands = self._state_merged(want, have) + elif state == "replaced": + commands = self._state_replaced(want, have) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + commands.extend(self._state_deleted(want, have)) + + commands.extend(self._state_merged(want, have)) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + updates = dict_diff(have, want) + if updates: + for key, value in iteritems(flatten_dict(remove_empties(updates))): + commands.append(self._compute_commands(key, value)) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + for key, value in iteritems( + flatten_dict(dict_delete(have, remove_empties(want))), + ): + cmd = self._compute_commands(key, value, remove=True) + if cmd: + commands.append(cmd) + + return commands + + def _compute_commands(self, key, value=None, remove=False): + if key in ["holdtime", "reinit", "timer"]: + cmd = "lldp {0} {1}".format(key, value) + if remove: + return "no {0}".format(cmd) + else: + return cmd + + elif key == "subinterfaces": + cmd = "lldp subinterfaces enable" + if value and not remove: + return cmd + elif (not value and not remove) or (value and remove): + return "no {0}".format(cmd) + + else: + cmd = "lldp tlv-select {0} disable".format(key.replace("_", "-")) + if not value and not remove: + return cmd + elif (value and not remove) or (not value and remove): + return "no {0}".format(cmd) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000..93dc42f4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,277 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_lldp_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + remove_empties, + search_obj_in_list, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + dict_delete, + flatten_dict, + pad_commands, +) + + +class Lldp_interfaces(ConfigBase): + """ + The iosxr_lldp_interfaces class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["lldp_interfaces"] + + def __init__(self, module): + super(Lldp_interfaces, self).__init__(module) + + def get_lldp_interfaces_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + lldp_interfaces_facts = facts["ansible_network_resources"].get( + "lldp_interfaces", + ) + if not lldp_interfaces_facts: + return [] + return lldp_interfaces_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + else: + existing_lldp_interfaces_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lldp_interfaces_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + 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_lldp_interfaces_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_lldp_interfaces_facts + if result["changed"]: + result["after"] = changed_lldp_interfaces_facts + elif self.state == "gathered": + result["gathered"] = changed_lldp_interfaces_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_lldp_interfaces_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_lldp_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + state = self._module.params["state"] + commands = [] + if state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "overridden": + commands.extend(self._state_overridden(want, have)) + + elif state == "deleted": + if not want: + for intf in have: + commands.extend( + self._state_deleted({"name": intf["name"]}, intf), + ) + else: + for item in want: + obj_in_have = search_obj_in_list(item["name"], have) + commands.extend(self._state_deleted(item, obj_in_have)) + + else: + for item in want: + name = item["name"] + obj_in_have = search_obj_in_list(name, have) + + if state in ("merged", "rendered"): + commands.extend(self._state_merged(item, obj_in_have)) + + elif state == "replaced": + commands.extend(self._state_replaced(item, obj_in_have)) + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + replaced_commands = [] + merged_commands = [] + + if have: + replaced_commands = self._state_deleted(want, have) + + merged_commands = self._state_merged(want, have) + + if merged_commands and replaced_commands: + del merged_commands[0] + + commands.extend(replaced_commands) + commands.extend(merged_commands) + + return commands + + def _state_overridden(self, want, have): + """The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for intf in have: + intf_in_want = search_obj_in_list(intf["name"], want) + if not intf_in_want: + commands.extend( + self._state_deleted({"name": intf["name"]}, intf), + ) + + for intf in want: + intf_in_have = search_obj_in_list(intf["name"], have) + commands.extend(self._state_replaced(intf, intf_in_have)) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + if not have: + have = {"name": want["name"]} + + for key, value in iteritems( + flatten_dict(remove_empties(dict_diff(have, want))), + ): + commands.append(self._compute_commands(key, value)) + + if commands: + pad_commands(commands, want["name"]) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + + for key, value in iteritems( + flatten_dict(dict_delete(have, remove_empties(want))), + ): + commands.append(self._compute_commands(key, value, remove=True)) + + if commands: + pad_commands(commands, have["name"]) + + return commands + + def _compute_commands(self, key, value=None, remove=False): + if key == "mac_address": + cmd = "lldp destination mac-address {0}".format(value) + if remove: + return "no {0}".format(cmd) + else: + return cmd + + else: + cmd = "lldp {0} disable".format(key) + if not value and not remove: + return cmd + elif (value and not remove) or (not value and remove): + return "no {0}".format(cmd) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/logging_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/logging_global.py new file mode 100644 index 00000000..ff790e54 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/logging_global/logging_global.py @@ -0,0 +1,227 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_logging_global config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.logging_global import ( + Logging_globalTemplate, +) + + +class Logging_global(ResourceModule): + """ + The iosxr_logging_global config class + """ + + def __init__(self, module): + super(Logging_global, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="logging_global", + tmplt=Logging_globalTemplate(), + ) + self.parsers = [ + "archive.device", + "archive.frequency", + "archive.severity", + "archive.archive_size", + "archive.archive_length", + "archive.file_size", + "buffered.size", + "buffered.severity", + "buffered.discriminator", + "console.severity", + "correlator.buffer_size", + "events.threshold", + "events.buffer_size", + "events.display_location", + "events.severity", + "facility", + "hostnameprefix", + "format", + "ipv4.dscp", + "ipv6.dscp", + "ipv4.precedence", + "ipv6.precedence", + "localfilesize", + "suppress.duplicates", + "suppress.apply_rule", + "monitor.severity", + "monitor.discriminator", + "history.size", + "history.severity", + "trap.severity", + "trap.state", + "monitor.state", + "history.state", + "console.state", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self.list_to_dict(self.want) + haved = self.list_to_dict(self.have) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + wantd = {} + + self._compare(want=wantd, have=haved) + if self.state in ["overridden", "replaced"]: + self.commands = [each for each in self.commands if "no" in each] + [ + each for each in self.commands if "no" not in each + ] + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Logging_global network resource. + """ + self.compare(parsers=self.parsers, want=want, have=have) + self._compare_lists(want, have) + + def _compare_lists(self, want, have): + """ + Handles list attributes from config_data + """ + for x in [ + "hosts", + "files", + "source_interfaces", + "tls_servers", + "correlator.rule_sets", + "correlator.rules", + "events.filter_match", + "buffered.discriminator", + "monitor.discriminator", + "console.discriminator", + ]: + wantx = want.get(x, {}) + havex = have.get(x, {}) + if "." in x: + complex_parser = x.split(".") + wantx = want.get(complex_parser[0], {}).get( + complex_parser[1], + {}, + ) + havex = have.get(complex_parser[0], {}).get( + complex_parser[1], + {}, + ) + + if x in ["tls_servers", "correlator.rules"]: + # handling complex parsers for replaced and overridden state + + for key, wentry in iteritems(wantx): + hentry = havex.pop(key, {}) + updates = dict_diff(hentry, wentry) + if updates and x == "tls_servers": + updates.update(name=wentry["name"]) + self.addcmd(updates, x) + elif updates and x == "correlator.rules": + updates.update(rule_type=wentry["rule_type"]) + updates.update(rule_name=wentry["rule_name"]) + self.addcmd(updates, x) + else: + for key, wentry in iteritems(wantx): + hentry = havex.pop(key, {}) + if wentry != hentry: + self.addcmd(wentry, x) + + for key, hentry in iteritems(havex): + self.addcmd(hentry, x, negate=True) + + def list_to_dict(self, config): + + data = deepcopy(config) + if "tls_servers" in data: + data["tls_servers"] = {x["name"]: x for x in data["tls_servers"]} + + if "source_interfaces" in data: + data["source_interfaces"] = { + x["interface"] + "_" + x.get("vrf", ""): x for x in data["source_interfaces"] + } + + if "files" in data: + data["files"] = {x["name"]: x for x in data["files"]} + + if "hosts" in data: + data["hosts"] = {x["host"]: x for x in data["hosts"]} + if "events" in data: + if "filter_match" in data["events"]: + data["events"]["filter_match"] = { + x: {"match": x} for x in data["events"]["filter_match"] + } + + if "correlator" in data: + if "rules" in data["correlator"]: + data["correlator"]["rules"] = { + x["rule_name"]: x for x in data["correlator"]["rules"] + } + if "rule_sets" in data["correlator"]: + rule_sets = deepcopy(data["correlator"]["rule_sets"]) + data["correlator"]["rule_sets"] = dict() + for x in rule_sets: + if len(x.get("rulename", [])) > 0: + for y in x.get("rulename"): + new_data = {"rulename": y, "name": x["name"]} + data["correlator"]["rule_sets"].update( + {x["name"] + "_" + y: new_data}, + ) + + else: + data["correlator"]["rule_sets"].update({x["name"]: x}) + + for x in ["buffered", "monitor", "console"]: + if x in data: + if "discriminator" in data[x]: + data[x]["discriminator"] = { + x["match_params"] + "_" + x["name"]: x for x in data[x]["discriminator"] + } + return data diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/ntp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/ntp_global.py new file mode 100644 index 00000000..5ec1789b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ntp_global/ntp_global.py @@ -0,0 +1,188 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_ntp_global config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ntp_global import ( + Ntp_globalTemplate, +) + + +class Ntp_global(ResourceModule): + """ + The iosxr_ntp_global config class + """ + + def __init__(self, module): + super(Ntp_global, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="ntp_global", + tmplt=Ntp_globalTemplate(), + ) + self.parsers = [ + "access_group.ipv4.peer", + "access_group.ipv4.serve", + "access_group.ipv4.serve_only", + "access_group.ipv4.query_only", + "access_group.ipv6.peer", + "access_group.ipv6.serve", + "access_group.ipv6.serve_only", + "access_group.ipv6.query_only", + "authenticate", + "log_internal_sync", + "broadcastdelay", + "drift.aging_time", + "drift.file", + "ipv4.dscp", + "ipv4.precedence", + "ipv6.dscp", + "ipv6.precedence", + "max_associations", + "master.stratum", + "passive", + "update_calendar", + "source_interface", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self._ntp_list_to_dict(self.want) + haved = self._ntp_list_to_dict(self.have) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd + if self.state == "deleted": + wantd = {} + + self._compare(want=wantd, have=haved) + if self.state in ["overridden", "replaced"]: + self.commands = [each for each in self.commands if "no" in each] + [ + each for each in self.commands if "no" not in each + ] + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Ntp_global network resource. + """ + self._compare_lists(want=want, have=have) + self.compare(parsers=self.parsers, want=want, have=have) + + def _compare_lists(self, want, have): + keys = [ + "authentication_keys", + "peers", + "servers", + "trusted_keys", + "interfaces", + "source_vrfs", + "access_group.vrfs", + ] + for x in keys: + if "." in x: + ag_vrf_list = x.split(".") + wantx = want.get(ag_vrf_list[0], {}).get(ag_vrf_list[1], {}) + havex = have.get(ag_vrf_list[0], {}).get(ag_vrf_list[1], {}) + x = ag_vrf_list[1] + else: + wantx = want.get(x, {}) + havex = have.get(x, {}) + + for wkey, wentry in iteritems(wantx): + hentry = havex.pop(wkey, {}) + if wentry != hentry: + if x == "interfaces": + updates = dict_diff(hentry, wentry) + updates.update(name=wentry.get("name")) + updates.update(vrf=wentry.get("vrf", "")) + self.addcmd(updates, x) + else: + self.addcmd(wentry, x) + + # remove superfluos config + for _hkey, hentry in iteritems(havex): + if x == "interfaces": + if "vrf" in hentry: + self.commands.append( + "no ntp interface {0} vrf {1}".format( + _hkey.split("_")[0], + _hkey.split("_")[1], + ), + ) + else: + self.commands.append( + "no ntp interface {0}".format(_hkey.split("_")[0]), + ) + else: + self.addcmd(hentry, x, negate=True) + + def _ntp_list_to_dict(self, data): + """Convert all list to dicts to dicts + of dicts + """ + tmp = deepcopy(data) + if "access_group" in tmp: + if "vrfs" in tmp["access_group"]: + tmp["access_group"]["vrfs"] = {i["name"]: i for i in tmp["access_group"]["vrfs"]} + if "interfaces" in tmp: + tmp["interfaces"] = {i["name"] + "_" + i.get("vrf", ""): i for i in tmp["interfaces"]} + if "peers" in tmp: + tmp["peers"] = {i["peer"] + "_" + i.get("vrf", ""): i for i in tmp["peers"]} + if "servers" in tmp: + tmp["servers"] = {i["server"] + "_" + i.get("vrf", ""): i for i in tmp["servers"]} + + pkey = { + "authentication_keys": "id", + "trusted_keys": "key_id", + "source_vrfs": "vrf", + } + for k in pkey.keys(): + if k in tmp: + tmp[k] = {i[pkey[k]]: i for i in tmp[k]} + return tmp diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/ospf_interfaces.py new file mode 100644 index 00000000..a80fe215 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospf_interfaces/ospf_interfaces.py @@ -0,0 +1,236 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_ospf_interfaces config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospf_interfaces import ( + Ospf_interfacesTemplate, +) + + +class Ospf_interfaces(ResourceModule): + """ + The iosxr_ospf_interfaces config class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["ospf_interfaces"] + + def __init__(self, module): + super(Ospf_interfaces, self).__init__( + empty_fact_val=[], + facts_module=Facts(module), + module=module, + resource="ospf_interfaces", + tmplt=Ospf_interfacesTemplate(), + ) + self.parsers = [ + "authentication.message_digest", + "authentication.null_auth", + "authentication.message_digest.keychain", + "authentication_key", + "bfd.minimum_interval", + "bfd.multiplier", + "bfd.fast_detect.set", + "bfd.fast_detect.disable", + "bfd.fast_detect.strict_mode", + "cost", + "cost_fallback", + "dead_interval", + "demand_circuit", + "flood_reduction", + "hello_interval", + "link_down.set", + "link_down.disable", + "message_digest_key", + "mpls.set_ldp", + "mpls.ldp_sync", + "mpls.ldp_sync_disable", + "mtu_ignore", + "network", + "packet_size", + "passive", + "prefix_suppression.disable", + "prefix_suppression.secondary_address", + "priority", + "retransmit_interval", + "security.ttl_hops", + "security.ttl", + "transmit_delay", + ] + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = {entry["name"]: entry for entry in self.want} + haved = {entry["name"]: entry for entry in self.have} + + # turn all lists of dicts into dicts prior to merge + for entry in wantd, haved: + self._ospf_int_list_to_dict(entry) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + have_int = [] + if wantd == {}: + for k, have in iteritems(haved): + self._remove_ospf_int(have) + + for k, have in iteritems(haved): + if k in wantd: + have_int.append(k) + self._remove_ospf_int(have) + wantd = {} + + # remove superfluous config for overridden and deleted + if self.state == "overridden": + for k, have in iteritems(haved): + if k not in wantd: + self._remove_ospf_int(have) + if self.state != "deleted": + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _remove_ospf_int(self, entry): + int_name = entry.get("name", {}) + int_addr = entry.get("address_family", {}) + for k, addr in iteritems(int_addr): + for key, value in addr["processes"].items(): + rem_entry = { + "name": int_name, + "afi": addr["afi"], + "process": value["process_id"], + "area": value["area"], + } + self.addcmd(rem_entry, "name", True) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Ospf_interfaces network resource. + """ + self._compare_interface(want=want, have=have) + + self._compare_addr_family(want=want, have=have) + + def _compare_interface(self, want, have): + wdict = want.get("address_family", {}) + hdict = have.get("address_family", {}) + wname = want.get("name") + hname = have.get("name") + h_value = {} + + for key, w_value in iteritems(wdict): + if hdict and hdict.get(key): + h_value = hdict[key] + else: + h_value = None + w = { + "name": wname, + "type": w_value["afi"], + "address_family": w_value, + } + if h_value is not None: + h = { + "name": hname, + "type": h_value["afi"], + "address_family": h_value, + } + else: + h = {} + self.compare(parsers="name", want=w, have=h) + + def _compare_addr_family(self, want, have): + wdict = want.get("address_family", {}) + hdict = have.get("address_family", {}) + wname = want.get("name") + hname = have.get("name") + # Fetch the area info as that would be common to all the attributes per interface + for name, entry in iteritems(wdict): + w_process = {} + h_process = {} + for key, value in iteritems(entry): + if key == "processes": + for pname, pentry in iteritems(value): + w_process = pentry + for key, param in iteritems(entry): + w_addr = {"afi": name, key: param, "processes": w_process} + h_addr = {} + if hdict.get(name): + hdict_entry = hdict.get(name) + for item, value in iteritems(hdict_entry): + if item == "processes": + for pname, pentry in iteritems(value): + h_process = pentry + h_addr = { + "afi": name, + key: hdict[name].pop(key, {}), + "processes": h_process, + } + w = {"name": wname, "address_family": w_addr} + h = {"name": hname, "address_family": h_addr} + self.compare(parsers=self.parsers, want=w, have=h) + for name, entry in iteritems(hdict): + for key, param in iteritems(entry): + h_addr = {"afi": name, key: param} + w_addr = {} + w = {"name": wname, "address_family": w_addr} + h = {"name": hname, "address_family": h_addr} + self.compare(parsers=self.parsers, want=w, have=h) + + def _ospf_int_list_to_dict(self, entry): + for name, family in iteritems(entry): + if "address_family" in family: + family["address_family"] = { + entry["afi"]: entry for entry in family.get("address_family", []) + } + self._ospf_int_list_to_dict(family["address_family"]) + for name, ospf_processes in iteritems(entry): + if "processes" in ospf_processes: + ospf_processes["processes"] = { + entry["process_id"]: entry for entry in ospf_processes.get("processes", []) + } + self._ospf_int_list_to_dict(ospf_processes["processes"]) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/ospfv2.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/ospfv2.py new file mode 100644 index 00000000..4b2d15f7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv2/ospfv2.py @@ -0,0 +1,254 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_ospfv2 class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospfv2 import ( + Ospfv2Template, +) + + +class Ospfv2(ResourceModule): + """ + The ios_ospfv2 class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["ospfv2"] + + def __init__(self, module): + super(Ospfv2, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="ospfv2", + tmplt=Ospfv2Template(), + ) + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + self.gen_config() + self.run_commands() + + return self.result + + def gen_config(self): + """Select the appropriate function based on the state provided + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + if self.want: + wantd = { + (entry["process_id"], entry.get("vrf")): entry + for entry in self.want.get("processes", []) + } + else: + wantd = {} + if self.have: + haved = { + (entry["process_id"], entry.get("vrf")): entry + for entry in self.have.get("processes", []) + } + else: + haved = {} + + # turn all lists of dicts into dicts prior to merge + for thing in wantd, haved: + for _pid, proc in iteritems(thing): + for area in proc.get("areas", []): + virtual_link = {entry["id"]: entry for entry in area.get("virtual_link", [])} + if bool(virtual_link): + area["virtual_link"] = virtual_link + ranges = {entry["address"]: entry for entry in area.get("ranges", [])} + if bool(ranges): + area["ranges"] = ranges + + proc["areas"] = {entry["area_id"]: entry for entry in proc.get("areas", [])} + if proc.get("distribute_list"): + if "acls" in proc.get("distribute_list"): + proc["distribute_list"]["acls"] = { + entry["name"]: entry + for entry in proc["distribute_list"].get( + "acls", + [], + ) + } + + # if state is merged, merge want onto have + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, limit the have to anything in want + # set want to nothing + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + wantd = {} + + # delete processes first so we do run into "more than one" errors + if self.state == "deleted": + haved_del = deepcopy(haved) + want_process = {} + for k, t_want in iteritems(haved_del): + want_process["process_id"] = t_want.get("process_id") + if not (len(t_want) == 2 and not t_want.get("areas")): + self._compare(want=want_process, have=haved_del.get(k, {})) + if self.state == "overridden": + haved_del = deepcopy(haved) + want = {} + for k, t_want in iteritems(haved_del): + if k not in wantd: + want["process_id"] = t_want.get("process_id") + if not (len(t_want) == 2 and not t_want.get("areas")): + self._compare(want=want, have=haved_del.get(k, {})) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + parsers = [ + "bfd", + "cost", + "weight", + "passive", + "priority", + "protocol", + "auto_cost", + "bandwidth", + "flood_reduction", + "default_metric", + "default_weight", + "router_id", + "demand_circuit", + "packet_size", + "transmit_delay", + "summary_in", + "external_out", + "dead_interval", + "hello_interval", + "authentication", + "adjacency_stagger", + "retransmit_interval", + "mtu_ignore", + "bfd.fast_detect", + "capability", + "capability.opaque", + "admin_distance", + "ospf_distance", + "address_family_unicast", + "loopback_stub_network", + "authentication.message_digest", + "default_information_originate", + "link_down_fast_detect", + "nsr", + "database_filter", + "log_adjacency_changes", + "distribute_bgp_ls", + "distribute_link_state", + "max_lsa", + "max_metric", + "mpls_ldp", + "mpls_traffic_eng", + "microloop_avoidance", + "prefix_suppression", + "protocol_shutdown", + "timers.lsa", + "timers.graceful_shutdown", + "throttle.lsa_all", + "throttle.spf", + "throttle.fast_reroute", + "timers.pacing_flood", + ] + + if want != have: + self.addcmd(want or have, "pid", False) + self.compare(parsers, want, have) + self._areas_compare(want, have) + + def _areas_compare(self, want, have): + wareas = want.get("areas", {}) + hareas = have.get("areas", {}) + for name, entry in iteritems(wareas): + self._area_compare(want=entry, have=hareas.pop(name, {})) + for name, entry in iteritems(hareas): + self._area_compare(want={}, have=entry) + + def _area_compare(self, want, have): + parsers = [ + "area.authentication", + "area.authentication_key", + "area.authentication.message_digest", + "area.mpls_traffic_eng", + "area.mpls_ldp", + "area.bfd", + "area.bfd.fast_detect", + "area.nssa", + "area.nssa.default_information_originate", + "area.nssa.translate", + "area.default_cost", + "area.stub", + "area.ranges", + "area.cost", + "area.dead_interval", + "area.hello_interval", + "area.transmit_delay", + "area.mtu_ignore", + "area.packet_size", + "area.priority", + "area.weight", + "area.external_out", + "area.summary_in", + "area.demand_circuit", + "area.passive", + ] + self.compare(parsers=parsers, want=want, have=have) + self._areas_compare_virtual_link(want, have) + + def _areas_compare_virtual_link(self, want, have): + wvlinks = want.get("virtual_link", {}) + hvlinks = have.get("virtual_link", {}) + for name, entry in iteritems(wvlinks): + self._area_compare_virtual_link( + want=entry, + have=hvlinks.pop(name, {}), + ) + for name, entry in iteritems(hvlinks): + self._area_compare_virtual_link(want={}, have=entry) + + def _area_compare_virtual_link(self, want, have): + parsers = [ + "virtual_link.authentication", + "virtual_link.authentication_key", + "virtual_link.authentication.message_digest", + "virtual_link.hello_interval", + "virtual_link.dead_interval", + "virtual_link.retransmit_interval", + ] + self.compare(parsers=parsers, want=want, have=have) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/ospfv3.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/ospfv3.py new file mode 100644 index 00000000..05ce4247 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ospfv3/ospfv3.py @@ -0,0 +1,247 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospfv3 import ( + Ospfv3Template, +) + + +class Ospfv3(ResourceModule): + """ + The ios_ospfv3 class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["ospfv3"] + + def __init__(self, module): + super(Ospfv3, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="ospfv3", + tmplt=Ospfv3Template(), + ) + + def execute_module(self): + """Execute the module + :rtype: A dictionary + :returns: The result from module execution + """ + self.gen_config() + self.run_commands() + + return self.result + + def gen_config(self): + """Select the appropriate function based on the state provided + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + if self.want: + wantd = { + (entry["process_id"], entry.get("vrf")): entry + for entry in self.want.get("processes", []) + } + else: + wantd = {} + if self.have: + haved = { + (entry["process_id"], entry.get("vrf")): entry + for entry in self.have.get("processes", []) + } + else: + haved = {} + + # turn all lists of dicts into dicts prior to merge + for thing in wantd, haved: + for _pid, proc in iteritems(thing): + for area in proc.get("areas", []): + virtual_link = {entry["id"]: entry for entry in area.get("virtual_link", [])} + if bool(virtual_link): + area["virtual_link"] = virtual_link + ranges = {entry["address"]: entry for entry in area.get("ranges", [])} + if bool(ranges): + area["ranges"] = ranges + + proc["areas"] = {entry["area_id"]: entry for entry in proc.get("areas", [])} + if proc.get("distribute_list"): + if "acls" in proc.get("distribute_list"): + proc["distribute_list"]["acls"] = { + entry["name"]: entry + for entry in proc["distribute_list"].get( + "acls", + [], + ) + } + + # if state is merged, merge want onto have + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, limit the have to anything in want + # set want to nothing + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + wantd = {} + + # delete processes first so we do run into "more than one" errors + if self.state == "deleted": + haved_del = deepcopy(haved) + want_process = {} + for k, t_want in iteritems(haved_del): + want_process["process_id"] = t_want.get("process_id") + if not (len(t_want) == 2 and not t_want.get("areas")): + self._compare(want=want_process, have=haved_del.get(k, {})) + if self.state == "overridden": + haved_del = deepcopy(haved) + want = {} + for k, t_want in iteritems(haved_del): + if k not in wantd: + want["process_id"] = t_want.get("process_id") + if not (len(t_want) == 2 and not t_want.get("areas")): + self._compare(want=want, have=haved_del.get(k, {})) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + parsers = [ + "bfd.minimum_interval", + "bfd.multiplier", + "cost", + "weight", + "passive", + "priority", + "protocol", + "auto_cost", + "bandwidth", + "flood_reduction", + "default_metric", + "default_weight", + "router_id", + "demand_circuit", + "packet_size", + "transmit_delay", + "dead_interval", + "hello_interval", + "authentication", + "retransmit_interval", + "mtu_ignore", + "bfd.fast_detect", + "capability", + "capability.opaque", + "admin_distance", + "ospf_distance", + "address_family_unicast", + "loopback_stub_network", + "authentication.ipsec", + "default_information_originate", + "link_down_fast_detect", + "nsr", + "database_filter", + "log_adjacency", + "distribute_bgp_ls", + "distribute_link_state", + "max_lsa", + "max_metric", + "mpls_ldp", + "mpls_traffic_eng", + "microloop_avoidance", + "prefix_suppression", + "protocol_shutdown", + "timers.lsa", + "timers.graceful_shutdown", + "throttle.lsa_all", + "throttle.spf", + "throttle.fast_reroute", + "timers.pacing_flood", + ] + + if want != have: + self.addcmd(want or have, "pid", False) + self.compare(parsers, want, have) + self._areas_compare(want, have) + + def _areas_compare(self, want, have): + wareas = want.get("areas", {}) + hareas = have.get("areas", {}) + for name, entry in iteritems(wareas): + self._area_compare(want=entry, have=hareas.pop(name, {})) + for name, entry in iteritems(hareas): + self._area_compare(want={}, have=entry) + + def _area_compare(self, want, have): + parsers = [ + "area.authentication", + "area.authentication.ipsec", + "area.mpls_traffic_eng", + "area.mpls_ldp", + "area.bfd.minimum_interval", + "area.bfd.multiplier", + "area.bfd.fast_detect", + "area.nssa", + "area.nssa.default_information_originate", + "area.nssa.translate", + "area.default_cost", + "area.stub", + "area.ranges", + "area.cost", + "area.dead_interval", + "area.hello_interval", + "area.transmit_delay", + "area.mtu_ignore", + "area.packet_size", + "area.priority", + "area.weight", + "area.external_out", + "area.summary_in", + "area.demand_circuit", + "area.passive", + ] + self.compare(parsers=parsers, want=want, have=have) + self._areas_compare_virtual_link(want, have) + + def _areas_compare_virtual_link(self, want, have): + wvlinks = want.get("virtual_link", {}) + hvlinks = have.get("virtual_link", {}) + for name, entry in iteritems(wvlinks): + self._area_compare_virtual_link( + want=entry, + have=hvlinks.pop(name, {}), + ) + for name, entry in iteritems(hvlinks): + self._area_compare_virtual_link(want={}, have=entry) + + def _area_compare_virtual_link(self, want, have): + parsers = [ + "virtual_link.authentication", + "virtual_link.authentication_key", + "virtual_link.authentication.message_digest", + "virtual_link.hello_interval", + "virtual_link.dead_interval", + "virtual_link.retransmit_interval", + ] + self.compare(parsers=parsers, want=want, have=have) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/ping.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/ping.py new file mode 100644 index 00000000..ce2a5229 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/ping/ping.py @@ -0,0 +1,99 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_ping config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import run_commands +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ping import ( + PingTemplate, +) + + +class Ping: + """ + The iosxr_ping config class + """ + + def __init__(self, module): + self.module = module + self.result = {} + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + self.generate_command() + res = self.run_command() + return self.process_result(res) + + def build_ping(self, params): + tmplt = PingTemplate() + params = utils.remove_empties(params) + cmd = tmplt.render(params, "rate", False) + return cmd + + def validate_results(self, module, loss, results): + """ + This function is used to validate whether the ping results were unexpected per "state" param. + """ + state = module.params["state"] + if state == "present" and loss == 100: + module.fail_json(msg="Ping failed unexpectedly", **results) + elif state == "absent" and loss < 100: + module.fail_json(msg="Ping succeeded unexpectedly", **results) + + def generate_command(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + warnings = list() + if warnings: + self.result["warnings"] = warnings + self.result["commands"] = self.build_ping(self.module.params) + + def run_command(self): + ping_results = run_commands( + self.module, + commands=self.result["commands"], + ) + return ping_results + + def process_result(self, ping_results): + """ + Function used to parse the statistical information from the ping response. + Example: "Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/8 ms" + Returns the percent of packet loss, received packets, transmitted packets, and RTT data. + """ + + if type(ping_results) == list: + ping_results = ping_results[0] + + ping_data = PingTemplate(lines=ping_results.splitlines()) + obj = list(ping_data.parse().values()) + + self.result["packet_loss"] = obj[0].get("loss_percentage") + self.result["packets_rx"] = obj[0].get("rx") + self.result["packets_tx"] = obj[0].get("tx") + self.result["rtt"] = obj[0].get("rtt") + loss = obj[0].get("loss") + self.validate_results(self.module, loss, self.result) + return self.result diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/prefix_lists.py new file mode 100644 index 00000000..03ef3f11 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/prefix_lists/prefix_lists.py @@ -0,0 +1,141 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_prefix_lists config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.prefix_lists import ( + Prefix_listsTemplate, +) + + +class Prefix_lists(ResourceModule): + """ + The iosxr_prefix_lists config class + """ + + def __init__(self, module): + super(Prefix_lists, self).__init__( + empty_fact_val=[], + facts_module=Facts(module), + module=module, + resource="prefix_lists", + tmplt=Prefix_listsTemplate(), + ) + self.parsers = ["prefix", "description", "prefix_list"] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = {entry["afi"]: entry for entry in self.want} + haved = {entry["afi"]: entry for entry in self.have} + + self._prefix_list_to_dict(wantd) + self._prefix_list_to_dict(haved) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + wantd = {} + + # remove superfluous config for overridden and deleted + if self.state in ["overridden", "deleted"]: + for k, have in iteritems(haved): + if k not in wantd: + self._compare(want={}, have=have) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + # alligning cmd with negate cmd 1st followed by config cmd + if self.state in ["overridden", "replaced"]: + self.commands = [each for each in self.commands if "no" in each] + [ + each for each in self.commands if "no" not in each + ] + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Prefix_lists network resource. + """ + self._compare_plists( + want.get("prefix_lists", {}), + have.get("prefix_lists", {}), + ) + + def _compare_plists(self, want, have): + for wk, wentry in iteritems(want): + hentry = have.pop(wk, {}) + # compare sequences + self._compare_seqs( + wentry.pop("entries", {}), + hentry.pop("entries", {}), + ) + + # remove remaining prefix lists + for h in have.values(): + self.commands.append( + "no {0} prefix-list {1}".format(h["afi"], h["name"]), + ) + + def _compare_seqs(self, want, have): + for wseq, wentry in iteritems(want): + hentry = have.pop(wseq, {}) + self.compare(parsers=self.parsers, want=wentry, have=hentry) + + # remove remaining entries from have prefix list + for hseq in have.values(): + self.compare(parsers=self.parsers, want={}, have=hseq) + + def _prefix_list_to_dict(self, entry): + for afi, value in iteritems(entry): + if "prefix_lists" in value: + for plist in value["prefix_lists"]: + plist.update({"afi": afi}) + if "entries" in plist: + for seq in plist["entries"]: + seq.update({"afi": afi, "name": plist["name"]}) + plist["entries"] = {x["sequence"]: x for x in plist["entries"]} + value["prefix_lists"] = { + (entry["name"], afi): entry for entry in value["prefix_lists"] + } diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/snmp_server.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/snmp_server.py new file mode 100644 index 00000000..9ee3e1a1 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/snmp_server/snmp_server.py @@ -0,0 +1,397 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr_snmp_server config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + dict_merge, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.snmp_server import ( + Snmp_serverTemplate, +) + + +class Snmp_server(ResourceModule): + """ + The iosxr_snmp_server config class + """ + + def __init__(self, module): + super(Snmp_server, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="snmp_server", + tmplt=Snmp_serverTemplate(), + ) + self.parsers = [ + "chassis_id", + "correlator.buffer_size", + "contact", + "ifindex", + "ipv4.dscp", + "ipv6.dscp", + "ipv4.precedence", + "ipv6.precedence", + "location", + "logging_threshold_oid_processing", + "logging_threshold_pdu_processing", + "mib_bulkstat_max_procmem_size", + "mroutemib_send_all_vrf", + "oid_poll_stats", + "overload_control", + "packetsize", + "queue_length", + "throttle_time", + "trap_source", + "trap_timeout", + "drop.report_IPv4", + "drop.report_IPv6", + "drop.unknown_user", + "ifmib.internal_cache_max_duration", + "ifmib.ipsubscriber", + "ifmib.stats", + "ifmib.ifalias_long", + "inform.timeout", + "inform.retries", + "inform.pending", + "notification_log_mib.size", + "notification_log_mib.default", + "notification_log_mib.disable", + "notification_log_mib.GlobalSize", + "trap.link_ietf", + "trap.authentication_vrf_disable", + "trap.throttle_time", + "timeouts.threshold", + "timeouts.pdu_stats", + "timeouts.subagent", + "timeouts.inQdrop", + "timeouts.duplicate", + "traps.addrpool.low", + "traps.addrpool.high", + "traps.bfd", + "traps.bgp.cbgp2", + "traps.bgp.updown", + "traps.bulkstat_collection", + "traps.bulkstat_transfer", + "traps.bridgemib", + "traps.copy_complete", + "traps.cisco_entity_ext", + "traps.config", + "traps.diameter.peerdown", + "traps.diameter.peerup", + "traps.diameter.protocolerror", + "traps.diameter.permanentfail", + "traps.diameter.transientfail", + "traps.entity", + "traps.entity_redundancy.all", + "traps.entity_redundancy.status", + "traps.entity_redundancy.switchover", + "traps.entity_state.operstatus", + "traps.entity_state.switchover", + "traps.flash.removal", + "traps.flash.insertion", + "traps.fru_ctrl", + "traps.hsrp", + "traps.ipsla", + "traps.ipsec.start", + "traps.ipsec.stop", + "traps.isakmp.start", + "traps.isakmp.stop", + "traps.isis", + "traps.l2tun.pseudowire_status", + "traps.l2tun.sessions", + "traps.l2tun.tunnel_up", + "traps.l2tun.tunnel_down", + "traps.l2vpn.all", + "traps.l2vpn.cisco", + "traps.l2vpn.vc_up", + "traps.l2vpn.vc_down", + "traps.msdp_peer_state_change", + "traps.ospf.retransmit.virt_packets", + "traps.ospf.retransmit.packets", + "traps.ospf.lsa.lsa_originate", + "traps.ospf.lsa.lsa_maxage", + "traps.ospf.errors.bad_packet", + "traps.ospf.errors.authentication_failure", + "traps.ospf.errors.config_error", + "traps.ospf.errors.virt_bad_packet", + "traps.ospf.errors.virt_authentication_failure", + "traps.ospf.errors.virt_config_error", + "traps.ospf.state_change.if_state_change", + "traps.ospf.state_change.neighbor_state_change", + "traps.ospf.state_change.virtif_state_change", + "traps.ospf.state_change.virtneighbor_state_change", + "traps.ospfv3.errors.bad_packet", + "traps.ospfv3.errors.authentication_failure", + "traps.ospfv3.errors.config_error", + "traps.ospfv3.errors.virt_config_error", + "traps.ospfv3.errors.virt_bad_packet", + "traps.ospfv3.state_change.neighbor_state_change", + "traps.ospfv3.state_change.virtif_state_change", + "traps.ospfv3.state_change.virtneighbor_state_change", + "traps.ospfv3.state_change.restart_status_change", + "traps.ospfv3.state_change.restart_helper_status_change", + "traps.ospfv3.state_change.restart_virtual_helper_status_change", + "traps.ospfv3.state_change.nssa_state_change", + "traps.power", + "traps.rf", + "traps.pim.neighbor_change", + "traps.pim.invalid_message_received", + "traps.pim.rp_mapping_change", + "traps.pim.interface_state_change", + "traps.rsvp.lost_flow", + "traps.rsvp.new_flow", + "traps.rsvp.all", + "traps.selective_vrf_download_role_change", + "traps.sensor", + "traps.vrrp_events", + "traps.syslog", + "traps.system", + "traps.subscriber.session_agg_access_interface", + "traps.subscriber.session_agg_node", + "traps.vpls.all", + "traps.vpls.full_clear", + "traps.vpls.full_raise", + "traps.vpls.status", + "traps.snmp.linkup", + "traps.snmp.linkdown", + "traps.snmp.coldstart", + "traps.snmp.warmstart", + "traps.snmp.authentication", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def handle_alieses(self, want): + for x in [want.get("groups", []), want.get("users", [])]: + for y in x: + if y.get("Ipv4_acl"): + del y["Ipv4_acl"] + if y.get("Ipv6_acl"): + del y["Ipv6_acl"] + return want + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + + self.want = self.handle_alieses(self.want) + wantd = self.list_to_dict(self.want) + haved = self.list_to_dict(self.have) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + wantd = {} + + self._compare(want=wantd, have=haved) + if self.state in ["overridden", "replaced"]: + self.commands = [each for each in self.commands if "no" in each] + [ + each for each in self.commands if "no" not in each + ] + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Logging_global network resource. + """ + self.compare(parsers=self.parsers, want=want, have=have) + self._compare_lists(want, have) + self._compare_vrfs(want, have) + + def _remove_snmp_server(self, begin): + for i in range(begin, len(self.commands)): + self.commands[i] = self.commands[i].replace("snmp-server ", "") + + def _compare_vrfs(self, want, have): + wvrfs = want.get("vrfs", {}) + hvrfs = have.get("vrfs", {}) + for name, entry in iteritems(wvrfs): + begin = len(self.commands) + vrf_have = hvrfs.pop(name, {}) + self._compare_lists(want=entry, have=vrf_have) + if len(self.commands) != begin: + self._remove_snmp_server(begin) + self.commands.insert( + begin, + self._tmplt.render( + {"vrf": entry.get("vrf")}, + "vrfs", + False, + ), + ) + for name, entry in iteritems(hvrfs): + self.addcmd(entry, "vrfs", True) + + def _compare_lists(self, want, have): + """ + Handles list attributes from config_data + """ + for x in [ + "communities", + "community_maps", + "correlator.rule_sets", + "correlator.rules", + "context", + "groups", + "hosts", + "interfaces", + "mib_object_lists", + "mib_schema", + "mib_bulkstat_transfer_ids", + "users", + "targets", + ]: + + wantx = want.get(x, {}) + havex = have.get(x, {}) + if "." in x: + complex_parser = x.split(".") + wantx = want.get(complex_parser[0], {}).get( + complex_parser[1], + {}, + ) + havex = have.get(complex_parser[0], {}).get( + complex_parser[1], + {}, + ) + + if x in [ + "interfaces", + "correlator.rules", + "mib_schema", + "mib_bulkstat_transfer_ids", + ]: + # handling complex parsers for replaced and overridden state + + for key, wentry in iteritems(wantx): + hentry = havex.pop(key, {}) + updates = dict_diff(hentry, wentry) + if updates and x in [ + "interfaces", + "mib_schema", + "mib_bulkstat_transfer_ids", + ]: + updates.update(name=wentry["name"]) + self.addcmd(updates, x) + elif updates and x == "correlator.rules": + updates.update(rule_name=wentry["rule_name"]) + self.addcmd(updates, x) + else: + for key, wentry in iteritems(wantx): + hentry = havex.pop(key, {}) + if wentry != hentry: + self.addcmd(wentry, x) + + for key, hentry in iteritems(havex): + self.addcmd(hentry, x, negate=True) + + def _host_list_to_dict(self, data): + host_dict = {} + host_data = deepcopy(data) + for el in host_data["hosts"]: + tr = "" + inf = "" + if el.get("traps"): + tr = "traps" + if el.get("informs"): + inf = "informs" + host_dict.update( + { + ( + el.get("host"), + el.get("community"), + el.get("version"), + inf, + tr, + el.get("udp_port"), + ): el, + }, + ) + return host_dict + + def list_to_dict(self, config): + + data = deepcopy(config) + + if data.get("vrfs"): + for x in data["vrfs"]: + if "context" in x: + x["context"] = {y: {"name": y} for y in x["context"]} + if "hosts" in x: + x["hosts"] = self._host_list_to_dict(x) + + pkey = { + "communities": "name", + "community_maps": "name", + "interfaces": "name", + "mib_schema": "name", + "groups": "group", + "mib_bulkstat_transfer_ids": "name", + "users": "user", + "vrfs": "vrf", + } + for k in pkey.keys(): + if k in data: + data[k] = {i[pkey[k]]: i for i in data[k]} + + if "correlator" in data: + if "rules" in data["correlator"]: + data["correlator"]["rules"] = { + x["rule_name"]: x for x in data["correlator"]["rules"] + } + if "rule_sets" in data["correlator"]: + data["correlator"]["rule_sets"] = { + x["name"]: x for x in data["correlator"]["rule_sets"] + } + + if "context" in data: + data["context"] = {x: {"name": x} for x in data["context"]} + if "mib_object_lists" in data: + data["mib_object_lists"] = {x: {"mib_object": x} for x in data["mib_object_lists"]} + if "targets" in data: + data["targets"] = { + x["name"] + x.get("vrf", "") + x.get("host", ""): x for x in data["targets"] + } + if "hosts" in data: + data["hosts"] = self._host_list_to_dict(data) + return data diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/static_routes.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/static_routes.py new file mode 100644 index 00000000..b558f01a --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/config/static_routes/static_routes.py @@ -0,0 +1,560 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_static_routes class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( + ConfigBase, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + dict_merge, + remove_empties, + search_obj_in_list, + to_list, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import Facts + + +class Static_routes(ConfigBase): + """ + The iosxr_static_routes class + """ + + gather_subset = ["!all", "!min"] + + gather_network_resources = ["static_routes"] + + def __init__(self, module): + super(Static_routes, self).__init__(module) + + def get_static_routes_facts(self, data=None): + """Get the 'facts' (the current configuration) + + :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, + ) + static_routes_facts = facts["ansible_network_resources"].get( + "static_routes", + ) + if not static_routes_facts: + return [] + return static_routes_facts + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {"changed": False} + warnings = list() + commands = list() + + if self.state in self.ACTION_STATES: + existing_static_routes_facts = self.get_static_routes_facts() + else: + existing_static_routes_facts = [] + + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_static_routes_facts)) + + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True + + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_static_routes_facts = self.get_static_routes_facts() + + 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_static_routes_facts( + data=running_config, + ) + + if self.state in self.ACTION_STATES: + result["before"] = existing_static_routes_facts + if result["changed"]: + result["after"] = changed_static_routes_facts + + elif self.state == "gathered": + result["gathered"] = changed_static_routes_facts + + result["warnings"] = warnings + return result + + def set_config(self, existing_static_routes_facts): + """Collect the configuration from the args passed to the module, + collect the current configuration (as a dict from facts) + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + want = self._module.params["config"] + have = existing_static_routes_facts + resp = self.set_state(want, have) + return to_list(resp) + + def set_state(self, want, have): + """Select the appropriate function based on the state provided + + :param want: the desired configuration as a dictionary + :param have: the current configuration as a dictionary + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + state = self._module.params["state"] + commands = [] + + if state in ("overridden", "merged", "replaced", "rendered") and not want: + self._module.fail_json( + msg="value of config parameter must not be empty for state {0}".format( + state, + ), + ) + + if state == "overridden": + commands.extend(self._state_overridden(want, have)) + + elif state == "deleted": + if not want: + if len(have) >= 1: + return "no router static" + + else: + for w_item in want: + obj_in_have = self._find_vrf(w_item, have) + if obj_in_have: + commands.extend( + self._state_deleted( + remove_empties(w_item), + obj_in_have, + ), + ) + + else: + for w_item in want: + obj_in_have = self._find_vrf(w_item, have) + if state == "merged" or self.state == "rendered": + commands.extend( + self._state_merged( + remove_empties(w_item), + obj_in_have, + ), + ) + + elif state == "replaced": + commands.extend( + self._state_replaced( + remove_empties(w_item), + obj_in_have, + ), + ) + + if commands: + commands.insert(0, "router static") + + return commands + + def _state_replaced(self, want, have): + """The command generator when state is replaced + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + for want_afi in want.get("address_families", []): + have_afi = ( + self.find_af_context( + want_afi, + have.get("address_families", []), + ) + or {} + ) + update_commands = [] + for want_route in want_afi.get("routes", []): + have_route = ( + search_obj_in_list( + want_route["dest"], + have_afi.get("routes", []), + key="dest", + ) + or {} + ) + + rotated_have_next_hops = self.rotate_next_hops( + have_route.get("next_hops", {}), + ) + rotated_want_next_hops = self.rotate_next_hops( + want_route.get("next_hops", {}), + ) + + for key in rotated_have_next_hops.keys(): + if key not in rotated_want_next_hops: + cmd = "no {0}".format(want_route["dest"]) + for item in key: + if "." in item or ":" in item or "/" in item: + cmd += " {0}".format(item) + else: + cmd += " vrf {0}".format(item) + update_commands.append(cmd) + + for key, value in iteritems(rotated_want_next_hops): + if key in rotated_have_next_hops: + existing = True + have_exit_point_attribs = rotated_have_next_hops[key] + + else: + existing = False + have_exit_point_attribs = {} + + updates = dict_diff(have_exit_point_attribs, value) + + if updates or not existing: + update_commands.append( + self._compute_commands( + dest=want_route["dest"], + next_hop=key, + updates=updates, + ), + ) + + if update_commands: + update_commands.insert( + 0, + "address-family {0} {1}".format( + want_afi["afi"], + want_afi["safi"], + ), + ) + commands.extend(update_commands) + + if "vrf" in want and update_commands: + commands.insert(0, "vrf {0}".format(want["vrf"])) + + return commands + + def _state_overridden(self, want, have): + """The command generator when state is overridden + + :rtype: A list + :returns: the commands necessary to migrate the current configuration + to the desired configuration + """ + commands = [] + + # Iterate through all the entries, i.e., VRFs and Global entry in have + # and fully remove the ones that are not present in want and then call + # replaced + + for h_item in have: + w_item = self._find_vrf(h_item, want) + + # Delete all the top-level keys (VRFs/Global Route Entry) that are + # not specified in want. + if not w_item: + if "vrf" in h_item: + commands.append("no vrf {0}".format(h_item["vrf"])) + else: + for have_afi in h_item.get("address_families", []): + commands.append( + "no address-family {0} {1}".format( + have_afi["afi"], + have_afi["safi"], + ), + ) + + # For VRFs/Global Entry present in want, we also need to delete extraneous routes + # from them. We cannot reuse `_state_replaced` for this purpose since its scope is + # limited to replacing a single `dest`. + else: + del_cmds = [] + for have_afi in h_item.get("address_families", []): + want_afi = ( + self.find_af_context( + have_afi, + w_item.get("address_families", []), + ) + or {} + ) + update_commands = [] + for h_route in have_afi.get("routes", []): + w_route = ( + search_obj_in_list( + h_route["dest"], + want_afi.get("routes", []), + key="dest", + ) + or {} + ) + if not w_route: + update_commands.append( + "no {0}".format(h_route["dest"]), + ) + + if update_commands: + update_commands.insert( + 0, + "address-family {0} {1}".format( + want_afi["afi"], + want_afi["safi"], + ), + ) + del_cmds.extend(update_commands) + + if "vrf" in want and update_commands: + del_cmds.insert(0, "vrf {0}".format(want["vrf"])) + + commands.extend(del_cmds) + + # We finally call `_state_replaced` to replace exiting `dest` entries + # or add new ones as specified in want. + for w_item in want: + h_item = self._find_vrf(w_item, have) + commands.extend( + self._state_replaced(remove_empties(w_item), h_item), + ) + + return commands + + def _state_merged(self, want, have): + """The command generator when state is merged + + :rtype: A list + :returns: the commands necessary to merge the provided into + the current configuration + """ + commands = [] + + for want_afi in want.get("address_families", []): + have_afi = ( + self.find_af_context( + want_afi, + have.get("address_families", []), + ) + or {} + ) + + update_commands = [] + for want_route in want_afi.get("routes", []): + have_route = ( + search_obj_in_list( + want_route["dest"], + have_afi.get("routes", []), + key="dest", + ) + or {} + ) + + # convert the next_hops list of dictionaries to dictionary of + # dictionaries with (`dest_vrf`, `forward_router_address`, `interface`) tuple + # being the key for each dictionary. + # a combination of these 3 attributes uniquely identifies a route entry. + # in case `dest_vrf` is not specified, `forward_router_address` and `interface` + # become the unique identifier + rotated_have_next_hops = self.rotate_next_hops( + have_route.get("next_hops", {}), + ) + rotated_want_next_hops = self.rotate_next_hops( + want_route.get("next_hops", {}), + ) + + # for every dict in the want next_hops dictionaries, if the key + # is present in `rotated_have_next_hops`, we set `existing` to True, + # which means the the given want exit point exists and we run dict_diff + # on `value` which is basically all the other attributes of the exit point + # if the key is not present, it means that this is a new exit point + for key, value in iteritems(rotated_want_next_hops): + if key in rotated_have_next_hops: + existing = True + have_exit_point_attribs = rotated_have_next_hops[key] + + else: + existing = False + have_exit_point_attribs = {} + + updates = dict_diff(have_exit_point_attribs, value) + if updates or not existing: + update_commands.append( + self._compute_commands( + dest=want_route["dest"], + next_hop=key, + # dict_merge() is necessary to make sure that we + # don't end up overridding the entry and also to + # allow incremental updates + updates=dict_merge( + rotated_have_next_hops.get(key, {}), + updates, + ), + ), + ) + + if update_commands: + update_commands.insert( + 0, + "address-family {0} {1}".format( + want_afi["afi"], + want_afi["safi"], + ), + ) + commands.extend(update_commands) + + if "vrf" in want and update_commands: + commands.insert(0, "vrf {0}".format(want["vrf"])) + + return commands + + def _state_deleted(self, want, have): + """The command generator when state is deleted + + :rtype: A list + :returns: the commands necessary to remove the current configuration + of the provided objects + """ + commands = [] + if "address_families" not in want: + return ["no vrf {0}".format(want["vrf"])] + + else: + for want_afi in want.get("address_families", []): + have_afi = ( + self.find_af_context( + want_afi, + have.get("address_families", []), + ) + or {} + ) + if have_afi: + commands.append( + "no address-family {0} {1}".format( + have_afi["afi"], + have_afi["safi"], + ), + ) + if "vrf" in want and commands: + commands.insert(0, "vrf {0}".format(want["vrf"])) + + return commands + + def _find_vrf(self, item, entries): + """This method iterates through the items + in `entries` and returns the object that + matches `item`. + + :rtype: A dict + :returns: the obj in `entries` that matches `item` + """ + obj = {} + afi = item.get("vrf") + + if afi: + obj = search_obj_in_list(afi, entries, key="vrf") or {} + else: + for x in entries: + if "vrf" not in remove_empties(x): + obj = x + break + return obj + + def find_af_context(self, want_af_context, have_address_families): + """This method iterates through the have AFs + and returns the one that matches the want AF + + :rtype: A dict + :returns: the corresponding AF in have AFs + that matches the want AF + """ + for have_af in have_address_families: + if ( + have_af["afi"] == want_af_context["afi"] + and have_af["safi"] == want_af_context["safi"] + ): + return have_af + + def rotate_next_hops(self, next_hops): + """This method iterates through the list of + next hops for a given destination network + and converts it to a dictionary of dictionaries. + Each dictionary has a primary key indicated by the + tuple of `dest_vrf`, `forward_router_address` and + `interface` and the value of this key is a dictionary + that contains all the other attributes of the next hop. + + :rtype: A dict + :returns: A next_hops list in a dictionary of dictionaries format + """ + next_hops_dict = {} + + for entry in next_hops: + entry = entry.copy() + key_list = [] + + for x in ["dest_vrf", "forward_router_address", "interface"]: + if entry.get(x): + key_list.append(entry.pop(x)) + + key = tuple(key_list) + next_hops_dict[key] = entry + + return next_hops_dict + + def _compute_commands(self, dest, next_hop, updates=None): + """This method computes a static route entry command + from the specified `dest`, `next_hop` and `updates` + + :rtype: A str + :returns: A platform specific static routes command + """ + if not updates: + updates = {} + + command = dest + + for x in next_hop: + if "." in x or ":" in x or "/" in x: + command += " {0}".format(x) + else: + command += " vrf {0}".format(x) + + for key in sorted(updates): + if key == "admin_distance": + command += " {0}".format(updates[key]) + else: + command += " {0} {1}".format(key, updates[key]) + + return command diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py new file mode 100644 index 00000000..85193821 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acl_interfaces/acl_interfaces.py @@ -0,0 +1,81 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr acl_interfaces fact class +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 copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.acl_interfaces.acl_interfaces import ( + Acl_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.acl_interfaces import ( + Acl_interfacesTemplate, +) + + +class Acl_interfacesFacts(object): + """The iosxr acl_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Acl_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for acl_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_config(connection) + + config_parser = Acl_interfacesTemplate(lines=data.splitlines()) + entry = sorted( + list(config_parser.parse().values()), + key=lambda k, sk="name": k[sk], + ) + if entry: + for item in entry: + item["access_groups"] = sorted( + list(item["access_groups"].values()), + key=lambda k, sk="afi": k[sk], + ) + + ansible_facts["ansible_network_resources"].pop("acl_interfaces", None) + facts = {"acl_interfaces": []} + params = utils.validate_config(self.argument_spec, {"config": entry}) + for cfg in params["config"]: + facts["acl_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/acls.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/acls.py new file mode 100644 index 00000000..efb8d93c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/acls/acls.py @@ -0,0 +1,471 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr acls fact class +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 + +import re + +from collections import deque +from copy import deepcopy + +from ansible.module_utils._text import to_text +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.acls.acls import ( + AclsArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + isipaddress, +) + + +PROTOCOL_OPTIONS = { + "tcp": ("ack", "fin", "psh", "rst", "syn", "urg", "established"), + "igmp": ( + "dvmrp", + "host_query", + "host_report", + "mtrace", + "mtrace_response", + "pim", + "trace", + "v2_leave", + "v2_report", + "v3_report", + ), + "icmp": ( + "administratively_prohibited", + "alternate_address", + "conversion_error", + "dod_host_prohibited", + "dod_net_prohibited", + "echo", + "echo_reply", + "general_parameter_problem", + "host_isolated", + "host_precedence_unreachable", + "host_redirect", + "host_tos_redirect", + "host_tos_unreachable", + "host_unknown", + "host_unreachable", + "information_reply", + "information_request", + "mask_reply", + "mask_request", + "mobile_redirect", + "net_redirect", + "net_tos_redirect", + "net_tos_unreachable", + "net_unreachable", + "network_unknown", + "no_room_for_option", + "option_missing", + "packet_too_big", + "parameter_problem", + "port_unreachable", + "precedence_unreachable", + "protocol_unreachable", + "reassembly_timeout", + "redirect", + "router_advertisement", + "router_solicitation", + "source_quench", + "source_route_failed", + "time_exceeded", + "timestamp_reply", + "timestamp_request", + "traceroute", + "ttl_exceeded", + "unreachable", + ), + "icmpv6": ( + "address_unreachable", + "administratively_prohibited", + "beyond_scope_of_source_address", + "destination_unreachable", + "echo", + "echo_reply", + "erroneous_header_field", + "group_membership_query", + "group_membership_report", + "group_membership_termination", + "host_unreachable", + "nd_na", + "nd_ns", + "neighbor_redirect", + "no_route_to_destination", + "node_information_request_is_refused", + "node_information_successful_reply", + "packet_too_big", + "parameter_problem", + "port_unreachable", + "query_subject_is_IPv4address", + "query_subject_is_IPv6address", + "query_subject_is_domainname", + "reassembly_timeout", + "redirect", + "router_advertisement", + "router_renumbering", + "router_solicitation", + "rr_command", + "rr_result", + "rr_seqnum_reset", + "time_exceeded", + "ttl_exceeded", + "unknown_query_type", + "unreachable", + "unrecognized_next_header", + "unrecognized_option", + "whoareyou_reply", + "whoareyou_request", + ), +} + + +class AclsFacts(object): + """The iosxr acls fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = AclsArgs.argument_spec + spec = deepcopy(self.argument_spec) + + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_device_data(self, connection): + return connection.get("show access-lists afi-all") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for acls + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + data = self.get_device_data(connection) + + objs = [] + + acl_lines = data.splitlines() + # We iterate through the data and create a list of ACLs + # where each ACL is a dictionary in the following format: + # {'afi': 'ipv4', 'name': 'acl_1', 'aces': ['10 permit 172.16.0.0 0.0.255.255', '20 deny 192.168.34.0 0.0.0.255']} + if acl_lines: + acl, acls = {}, [] + for line in acl_lines: + if "matches" in line: + line = re.sub(r"\([^()]*\)", "", line) + if line.startswith("ip"): + if acl: + acls.append(acl) + acl = {"aces": []} + acl["afi"], acl["name"] = line.split()[0], line.split()[2] + else: + acl["aces"].append(line.strip()) + acls.append(acl) + + # Here we group the ACLs based on AFI + # { + # 'ipv6': [{'aces': ['10 permit ipv6 2000::/12 any'], 'name': 'acl_2'}], + # 'ipv4': [{'aces': ['10 permit 172.16.0.0 0.0.255.255', '20 deny 192.168.34.0 0.0.0.255'], 'name': 'acl_1'}, + # {'aces': ['20 deny 10.0.0.0/8 log'], 'name': 'acl_3'}] + # } + + grouped_acls = {"ipv4": [], "ipv6": []} + for acl in acls: + acl_copy = deepcopy(acl) + del acl_copy["afi"] + grouped_acls[acl["afi"]].append(acl_copy) + + # Now that we have the ACLs in a fairly structured format, + # we pass it on to render_config to convert it to model spec + for key, value in iteritems(grouped_acls): + obj = self.render_config(self.generated_spec, value) + if obj: + obj["afi"] = key + objs.append(obj) + + ansible_facts["ansible_network_resources"].pop("acls", None) + facts = {} + + facts["acls"] = [] + params = utils.validate_config(self.argument_spec, {"config": objs}) + for cfg in params["config"]: + facts["acls"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + config["acls"] = [] + + for item in conf: + acl = {"name": item["name"]} + aces = item.get("aces", []) + if aces: + acl["aces"] = [] + for ace in aces: + acl["aces"].append(self._render_ace(ace)) + config["acls"].append(acl) + + return utils.remove_empties(config) + + def _render_ace(self, ace): + """ + Parses an Access Control Entry (ACE) and converts it + into model spec + + :param ace: An ACE in device specific format + :rtype: dictionary + :returns: The ACE in structured format + """ + + def _parse_src_dest(rendered_ace, ace_queue, direction): + """ + Parses the ACE queue and populates address, wildcard_bits, + host or any keys in the source/destination dictionary of + ace dictionary, i.e., `rendered_ace`. + + :param rendered_ace: The dictionary containing the ACE in structured format + :param ace_queue: The ACE queue + :param direction: Specifies whether to populate `source` or `destination` + dictionary + """ + element = ace_queue.popleft() + if element == "host": + rendered_ace[direction] = {"host": ace_queue.popleft()} + elif element == "net-group": + rendered_ace[direction] = {"net_group": ace_queue.popleft()} + elif element == "port-group": + rendered_ace[direction] = {"port_group": ace_queue.popleft()} + elif element == "any": + rendered_ace[direction] = {"any": True} + + elif "/" in element: + rendered_ace[direction] = {"prefix": element} + + elif isipaddress(to_text(element)): + rendered_ace[direction] = { + "address": element, + "wildcard_bits": ace_queue.popleft(), + } + + def _parse_port_protocol(rendered_ace, ace_queue, direction): + """ + Parses the ACE queue and populates `port_protocol` dictionary in the + ACE dictionary, i.e., `rendered_ace`. + + :param rendered_ace: The dictionary containing the ACE in structured format + :param ace_queue: The ACE queue + :param direction: Specifies whether to populate `source` or `destination` + dictionary + """ + if len(ace_queue) > 0 and ace_queue[0] in ( + "eq", + "gt", + "lt", + "neq", + "range", + ): + element = ace_queue.popleft() + port_protocol = {} + + if element == "range": + port_protocol["range"] = { + "start": ace_queue.popleft(), + "end": ace_queue.popleft(), + } + else: + port_protocol[element] = ace_queue.popleft() + + if rendered_ace.get(direction): + rendered_ace[direction]["port_protocol"] = port_protocol + else: + rendered_ace[direction] = {"port_protocol": port_protocol} + + def _parse_protocol_options(rendered_ace, ace_queue, protocol): + """ + Parses the ACE queue and populates protocol specific options + of the required dictionary and updates the ACE dictionary, i.e., + `rendered_ace`. + + :param rendered_ace: The dictionary containing the ACE in structured format + :param ace_queue: The ACE queue + :param protocol: Specifies the protocol that will be populated under + `protocol_options` dictionary + """ + if len(ace_queue) > 0: + protocol_options = {protocol: {}} + + for match_bit in PROTOCOL_OPTIONS.get(protocol, ()): + if match_bit.replace("_", "-") in ace_queue: + protocol_options[protocol][match_bit] = True + ace_queue.remove(match_bit.replace("_", "-")) + + rendered_ace["protocol_options"] = protocol_options + + def _parse_match_options(rendered_ace, ace_queue): + """ + Parses the ACE queue and populates remaining options in the ACE dictionary, + i.e., `rendered_ace` + + :param rendered_ace: The dictionary containing the ACE in structured format + :param ace_queue: The ACE queue + """ + if len(ace_queue) > 0: + # We deepcopy the actual queue and iterate through the + # copied queue. However, we pop off the elements from + # the actual queue. Then, in every pass we update the copied + # queue with the current state of the original queue. + # This is done because a queue cannot be mutated during iteration. + copy_ace_queue = deepcopy(ace_queue) + + for element in copy_ace_queue: + if element == "precedence": + ace_queue.popleft() + rendered_ace["precedence"] = ace_queue.popleft() + + elif element == "dscp": + ace_queue.popleft() + dscp = {} + operation = ace_queue.popleft() + + if operation in ("eq", "gt", "neq", "lt", "range"): + if operation == "range": + dscp["range"] = { + "start": ace_queue.popleft(), + "end": ace_queue.popleft(), + } + else: + dscp[operation] = ace_queue.popleft() + else: + # `dscp` can be followed by either the dscp value itself or + # the same thing can be represented using "dscp eq <dscp_value>". + # In both cases, it would show up as {'dscp': {'eq': "dscp_value"}}. + dscp["eq"] = operation + + rendered_ace["dscp"] = dscp + + elif element in ("packet-length", "ttl"): + ace_queue.popleft() + element_dict = {} + operation = ace_queue.popleft() + + if operation == "range": + element_dict["range"] = { + "start": ace_queue.popleft(), + "end": ace_queue.popleft(), + } + else: + element_dict[operation] = ace_queue.popleft() + + rendered_ace[element.replace("-", "_")] = element_dict + + elif element in ( + "log", + "log-input", + "fragments", + "icmp-off", + "capture", + "destopts", + "authen", + "routing", + "hop-by-hop", + ): + rendered_ace[element.replace("-", "_")] = True + ace_queue.remove(element) + + copy_ace_queue = deepcopy(ace_queue) + + rendered_ace = {} + split_ace = ace.split() + + # Create a queue with each word in the ace + # We parse each element and pop it off the queue + ace_queue = deque(split_ace) + + # An ACE will always have a sequence number, even if + # it is not explicitly provided while configuring + sequence = int(ace_queue.popleft()) + rendered_ace["sequence"] = sequence + operation = ace_queue.popleft() + + if operation == "remark": + rendered_ace["remark"] = " ".join(split_ace[2:]) + + else: + rendered_ace["grant"] = operation + + # If the entry is a non-remark entry, the third element + # will always be the protocol specified. By default, it's + # the AFI. + rendered_ace["protocol"] = ace_queue.popleft() + + # Populate source dictionary + _parse_src_dest(rendered_ace, ace_queue, direction="source") + # Populate port_protocol key in source dictionary + _parse_port_protocol(rendered_ace, ace_queue, direction="source") + # Populate destination dictionary + _parse_src_dest(rendered_ace, ace_queue, direction="destination") + # Populate port_protocol key in destination dictionary + _parse_port_protocol( + rendered_ace, + ace_queue, + direction="destination", + ) + # Populate protocol_options dictionary + _parse_protocol_options( + rendered_ace, + ace_queue, + protocol=rendered_ace["protocol"], + ) + # Populate remaining match options' dictionaries + _parse_match_options(rendered_ace, ace_queue) + + # At this stage the queue should be empty + # If the queue is not empty, it means that + # we haven't been able to parse the entire ACE + # In this case, we add the whole unprocessed ACE + # to a key called `line` and send it back + if len(ace_queue) > 0: + rendered_ace = { + "sequence": sequence, + "line": " ".join(split_ace[1:]), + } + + return utils.remove_empties(rendered_ace) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/bgp_address_family.py new file mode 100644 index 00000000..dfcd66a3 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_address_family/bgp_address_family.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr bgp_address_family fact class +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 copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_address_family.bgp_address_family import ( + Bgp_address_familyArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_address_family import ( + Bgp_address_familyTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Bgp_address_familyFacts(object): + """The iosxr bgp_address_family facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Bgp_address_familyArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get("show running-config router bgp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Bgp_address_family network resource + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + if not data: + data = self.get_config(connection) + + nb_data = flatten_config(data, "neighbor") + data = flatten_config(nb_data, "vrf") + # parse native config using the Bgp_global template + bgp_global_parser = Bgp_address_familyTemplate(lines=data.splitlines()) + objs = bgp_global_parser.parse() + + af = objs.get("address_family") + if af: + self._post_parse(objs) + else: + objs["address_family"] = [] + + ansible_facts["ansible_network_resources"].pop( + "bgp_address_family", + None, + ) + + params = utils.remove_empties( + utils.validate_config(self.argument_spec, {"config": objs}), + ) + + facts["bgp_address_family"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def _post_parse(self, obj): + """Converts the intermediate data structure + to valid format as per argspec. + :param obj: dict + """ + af = obj.get("address_family", {}) + if af: + obj["address_family"] = list(af.values()) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/bgp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/bgp_global.py new file mode 100644 index 00000000..e2b5e4a2 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_global/bgp_global.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr bgp_global fact class +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 copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_global.bgp_global import ( + Bgp_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_global import ( + Bgp_globalTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Bgp_globalFacts(object): + """The iosxr bgp_global facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Bgp_globalArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get("show running-config router bgp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Bgp_global network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + bgp_global_config = [] + if not data: + data = self.get_config(connection) + neighbor_data = flatten_config(data, "neighbor") + rpki_server_data = flatten_config(neighbor_data, "rpki server") + data = flatten_config(rpki_server_data, "bgp confederation peers") + + # remove address_family configs from bgp_global + + start = False + for bgp_line in data.splitlines(): + if "address-family" in bgp_line: + start = True + if not start: + bgp_global_config.append(bgp_line) + if start and "!" in bgp_line: + start = False + + # parse native config using the Bgp_global template + bgp_global_parser = Bgp_globalTemplate( + lines=bgp_global_config, + module=self._module, + ) + objs = bgp_global_parser.parse() + + conf_peers = objs.get("bgp", {}).get("confederation", {}).get("peers", {}) + if conf_peers: + objs["bgp"]["confederation"]["peers"] = list(conf_peers.values()) + + vrfs = objs.get("vrfs", {}) + + # move global vals to their correct position in facts tree + # this is only needed for keys that are common between both global + # and VRF contexts + global_vals = vrfs.pop("vrf_", {}) + for key, value in iteritems(global_vals): + if objs.get(key): + objs[key].update(value) + else: + objs[key] = value + # transform vrfs into a list + if vrfs: + objs["vrfs"] = sorted( + list(objs["vrfs"].values()), + key=lambda k, sk="vrf": k[sk], + ) + for vrf in objs["vrfs"]: + self._post_parse(vrf) + else: + objs["vrfs"] = [] + + self._post_parse(objs) + + ansible_facts["ansible_network_resources"].pop("bgp_global", None) + + params = utils.remove_empties( + bgp_global_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["bgp_global"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def _post_parse(self, obj): + """Converts the intermediate data structure + to valid format as per argspec. + :param obj: dict + """ + neighbors = obj.get("neighbors", []) + if neighbors: + obj["neighbors"] = sorted( + list(neighbors.values()), + key=lambda k, sk="neighbor_address": k[sk], + ) + rpki_servers = obj.get("rpki", {}).get("servers", []) + if rpki_servers: + obj["rpki"]["servers"] = sorted( + list(rpki_servers.values()), + key=lambda k, sk="name": k[sk], + ) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/bgp_neighbor_address_family.py new file mode 100644 index 00000000..7824406e --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/bgp_neighbor_address_family/bgp_neighbor_address_family.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr bgp_neighbor_address_family fact class +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 copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_neighbor_address_family.bgp_neighbor_address_family import ( + Bgp_neighbor_address_familyArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.bgp_neighbor_address_family import ( + Bgp_neighbor_address_familyTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Bgp_neighbor_address_familyFacts(object): + """The iosxr bgp_neighbor_address_family facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Bgp_neighbor_address_familyArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get("show running-config router bgp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Bgp_address_family network resource + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + if not data: + data = self.get_config(connection) + nbr_data = flatten_config(data, "neighbor") + data = flatten_config(nbr_data, "vrf") + # parse native config using the Bgp_global template + bgp_global_parser = Bgp_neighbor_address_familyTemplate( + lines=data.splitlines(), + ) + objs = bgp_global_parser.parse() + + if objs: + top_lvl_nbrs = objs.get("vrfs", {}).pop("vrf_", {}) + objs["neighbors"] = self._post_parse(top_lvl_nbrs).get( + "neighbors", + [], + ) + + if "vrfs" in objs: + for vrf in objs["vrfs"].values(): + vrf["neighbors"] = self._post_parse(vrf)["neighbors"] + objs["vrfs"] = list(objs["vrfs"].values()) + + ansible_facts["ansible_network_resources"].pop( + "bgp_neighbor_address_family", + None, + ) + + params = utils.remove_empties( + utils.validate_config(self.argument_spec, {"config": objs}), + ) + + facts["bgp_neighbor_address_family"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def _post_parse(self, data): + """Converts the intermediate data structure + to valid format as per argspec. + :param obj: dict + """ + if "neighbors" in data: + data["neighbors"] = sorted( + list(data["neighbors"].values()), + key=lambda k, s="neighbor_address": k[s], + ) + for nbr in data["neighbors"]: + nbr["address_family"] = list(nbr["address_family"].values()) + return data diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/facts.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/facts.py new file mode 100644 index 00000000..4d7e7b10 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/facts.py @@ -0,0 +1,164 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The facts class for iosxr +this file validates each subset of facts and selectively +calls the appropriate facts gathering function +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import ( + FactsBase, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.acl_interfaces.acl_interfaces import ( + Acl_interfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.acls.acls import ( + AclsFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_address_family.bgp_address_family import ( + Bgp_address_familyFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_global.bgp_global import ( + Bgp_globalFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_neighbor_address_family.bgp_neighbor_address_family import ( + Bgp_neighbor_address_familyFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.hostname.hostname import ( + HostnameFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.interfaces.interfaces import ( + InterfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.l2_interfaces.l2_interfaces import ( + L2_InterfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.l3_interfaces.l3_interfaces import ( + L3_InterfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lacp.lacp import ( + LacpFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lacp_interfaces.lacp_interfaces import ( + Lacp_interfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lag_interfaces.lag_interfaces import ( + Lag_interfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.legacy.base import ( + Config, + Default, + Hardware, + Interfaces, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lldp_global.lldp_global import ( + Lldp_globalFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lldp_interfaces.lldp_interfaces import ( + Lldp_interfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.logging_global.logging_global import ( + Logging_globalFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ntp_global.ntp_global import ( + Ntp_globalFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospf_interfaces.ospf_interfaces import ( + Ospf_interfacesFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospfv2.ospfv2 import ( + Ospfv2Facts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospfv3.ospfv3 import ( + Ospfv3Facts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.prefix_lists.prefix_lists import ( + Prefix_listsFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.snmp_server.snmp_server import ( + Snmp_serverFacts, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.static_routes.static_routes import ( + Static_routesFacts, +) + + +FACT_LEGACY_SUBSETS = dict( + default=Default, + hardware=Hardware, + interfaces=Interfaces, + config=Config, +) +FACT_RESOURCE_SUBSETS = dict( + lacp=LacpFacts, + lacp_interfaces=Lacp_interfacesFacts, + lldp_global=Lldp_globalFacts, + lldp_interfaces=Lldp_interfacesFacts, + interfaces=InterfacesFacts, + l2_interfaces=L2_InterfacesFacts, + lag_interfaces=Lag_interfacesFacts, + l3_interfaces=L3_InterfacesFacts, + acl_interfaces=Acl_interfacesFacts, + acls=AclsFacts, + static_routes=Static_routesFacts, + ospfv2=Ospfv2Facts, + ospfv3=Ospfv3Facts, + ospf_interfaces=Ospf_interfacesFacts, + bgp_neighbor_address_family=Bgp_neighbor_address_familyFacts, + bgp_address_family=Bgp_address_familyFacts, + bgp_global=Bgp_globalFacts, + prefix_lists=Prefix_listsFacts, + logging_global=Logging_globalFacts, + ntp_global=Ntp_globalFacts, + snmp_server=Snmp_serverFacts, + hostname=HostnameFacts, +) + + +class Facts(FactsBase): + """The fact class for iosxr""" + + VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys()) + VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys()) + + def __init__(self, module): + super(Facts, self).__init__(module) + + def get_facts( + self, + legacy_facts_type=None, + resource_facts_type=None, + data=None, + ): + """Collect the facts for iosxr + + :param legacy_facts_type: List of legacy facts types + :param resource_facts_type: List of resource fact types + :param data: previously collected conf + :rtype: dict + :return: the facts gathered + """ + if self.VALID_RESOURCE_SUBSETS: + self.get_network_resources_facts( + FACT_RESOURCE_SUBSETS, + resource_facts_type, + data, + ) + + if self.VALID_LEGACY_GATHER_SUBSETS: + self.get_network_legacy_facts( + FACT_LEGACY_SUBSETS, + legacy_facts_type, + ) + + return self.ansible_facts, self._warnings diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/hostname.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/hostname.py new file mode 100644 index 00000000..832c426d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/hostname/hostname.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr hostname fact class +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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.hostname.hostname import ( + HostnameArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.hostname import ( + HostnameTemplate, +) + + +class HostnameFacts(object): + """The iosxr hostname facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = HostnameArgs.argument_spec + + def get_config(self, connection): + return connection.get("show running-config hostname") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Hostname network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_config(connection) + + # parse native config using the Hostname template + hostname_parser = HostnameTemplate( + lines=data.splitlines(), + module=self._module, + ) + objs = hostname_parser.parse() + + ansible_facts["ansible_network_resources"].pop("hostname", None) + + params = utils.remove_empties( + hostname_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["hostname"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/interfaces.py new file mode 100644 index 00000000..e89dbca2 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/interfaces/interfaces.py @@ -0,0 +1,115 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr interfaces fact class +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 + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.interfaces.interfaces import ( + InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + get_interface_type, +) + + +class InterfacesFacts(object): + """The iosxr interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = InterfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for interfaces + :param module: the module instance + :param connection: the device connection + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + objs = [] + if not data: + data = self.get_config(connection) + + # operate on a collection of resource x + config = ("\n" + data).split("\ninterface ") + for conf in config: + if conf: + obj = self.render_config(self.generated_spec, conf) + if obj: + objs.append(obj) + + facts = {} + if objs: + facts["interfaces"] = [] + params = utils.validate_config( + self.argument_spec, + {"config": objs}, + ) + for cfg in params["config"]: + facts["interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys from spec for null values + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + + config = deepcopy(spec) + match = re.search(r"^(\S+)", conf) + + intf = match.group(1) + if match.group(1).lower() == "preconfigure": + match = re.search(r"^(\S+) (.*)", conf) + if match: + intf = match.group(2) + + if get_interface_type(intf) == "unknown": + return {} + # populate the facts from the configuration + config["name"] = intf + config["description"] = utils.parse_conf_arg(conf, "description") + if utils.parse_conf_arg(conf, "speed"): + config["speed"] = int(utils.parse_conf_arg(conf, "speed")) + if utils.parse_conf_arg(conf, "mtu"): + config["mtu"] = int(utils.parse_conf_arg(conf, "mtu")) + config["duplex"] = utils.parse_conf_arg(conf, "duplex") + enabled = utils.parse_conf_cmd_arg(conf, "shutdown", False) + config["enabled"] = enabled if enabled is not None else True + + return utils.remove_empties(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py new file mode 100644 index 00000000..cdb1d72c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l2_interfaces/l2_interfaces.py @@ -0,0 +1,159 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr l2_interfaces fact class +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 + + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.l2_interfaces.l2_interfaces import ( + L2_InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import get_os_version +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + Version, + get_interface_type, +) + + +class L2_InterfacesFacts(object): + """The iosxr l2_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = L2_InterfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for l2_interfaces + :param module: the module instance + :param connection: the device connection + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + objs = [] + if not data: + data = self.get_config(connection) + + # operate on a collection of resource x + config = ("\n" + data).split("\ninterface ") + for conf in config: + if conf: + obj = self.render_config(self.generated_spec, conf) + if obj: + objs.append(obj) + facts = {} + if objs: + facts["l2_interfaces"] = [] + params = utils.validate_config( + self.argument_spec, + {"config": objs}, + ) + for cfg in params["config"]: + facts["l2_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys from spec for null values + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + match = re.search(r"^(\S+)", conf) + + intf = match.group(1) + + if match.group(1).lower() == "preconfigure": + match = re.search(r"^(\S+) (.*)", conf) + if match: + intf = match.group(2) + + if get_interface_type(intf) == "unknown": + return {} + + if intf.lower().startswith("gi"): + config["name"] = intf + + # populate the facts from the configuration + native_vlan = re.search(r"dot1q native vlan (\d+)", conf) + if native_vlan: + config["native_vlan"] = int(native_vlan.group(1)) + + dot1q = utils.parse_conf_arg(conf, "encapsulation dot1q") + os_version = get_os_version(self._module) + if os_version and Version(os_version) > Version("7.0.0"): + encapsulation = re.search( + r"encapsulation dot1q\s(\d+)\s*(second-dot1q\s\d+)?", + conf, + ) + if encapsulation: + config["encapsulation"]["dot1q"] = int( + encapsulation.group(1), + ) + if encapsulation.group(2): + config["encapsulation"]["second_dot1q"] = int( + encapsulation.group(2).split("second-dot1q ")[1], + ) + else: + config["q_vlan"] = [] + if dot1q: + config["q_vlan"].append(int(dot1q.split(" ")[0])) + if len(dot1q.split(" ")) > 1: + config["q_vlan"].append(int(dot1q.split(" ")[2])) + + if utils.parse_conf_cmd_arg(conf, "l2transport", True): + config["l2transport"] = True + if utils.parse_conf_arg(conf, "propagate"): + config["propagate"] = True + config["l2protocol"] = [] + + cdp = utils.parse_conf_arg(conf, "l2protocol cdp") + pvst = utils.parse_conf_arg(conf, "l2protocol pvst") + stp = utils.parse_conf_arg(conf, "l2protocol stp") + vtp = utils.parse_conf_arg(conf, "l2protocol vtp") + cpsv = utils.parse_conf_arg(conf, "l2protocol cpsv") + if cdp: + config["l2protocol"].append({"cdp": cdp}) + if pvst: + config["l2protocol"].append({"pvst": pvst}) + if stp: + config["l2protocol"].append({"stp": stp}) + if vtp: + config["l2protocol"].append({"vtp": vtp}) + if cpsv: + config["l2protocol"].append({"cpsv": cpsv}) + + return utils.remove_empties(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py new file mode 100644 index 00000000..bf5ce5f8 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/l3_interfaces/l3_interfaces.py @@ -0,0 +1,131 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr_l3_interfaces fact class +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 + + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.l3_interfaces.l3_interfaces import ( + L3_InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + get_interface_type, +) + + +class L3_InterfacesFacts(object): + """The iosxr_l3_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = L3_InterfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + objs = [] + + if not data: + data = self.get_config(connection) + # operate on a collection of resource x + config = ("\n" + data).split("\ninterface ") + for conf in config: + if conf: + obj = self.render_config(self.generated_spec, conf) + if obj: + objs.append(obj) + facts = {} + + if objs: + facts["l3_interfaces"] = [] + params = utils.validate_config( + self.argument_spec, + {"config": objs}, + ) + for cfg in params["config"]: + facts["l3_interfaces"].append(utils.remove_empties(cfg)) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys from spec for null values + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + match = re.search(r"^(\S+)", conf) + + intf = match.group(1) + if match.group(1).lower() == "preconfigure": + match = re.search(r"^(\S+) (.*)", conf) + if match: + intf = match.group(2) + + if get_interface_type(intf) == "unknown": + return {} + + # populate the facts from the configuration + config["name"] = intf + + # Get the configured IPV4 details + ipv4 = [] + ipv4_all = re.findall(r"ipv4 address (\S+.*)", conf) + for each in ipv4_all: + each_ipv4 = dict() + if "secondary" in each: + each_ipv4["address"] = each.split(" secondary")[0] + each_ipv4["secondary"] = True + else: + each_ipv4["address"] = each + ipv4.append(each_ipv4) + config["ipv4"] = ipv4 + + # Get the configured IPV6 details + ipv6 = [] + ipv6_all = re.findall(r"ipv6 address (\S+)", conf) + for each in ipv6_all: + each_ipv6 = dict() + each_ipv6["address"] = each + ipv6.append(each_ipv6) + config["ipv6"] = ipv6 + + return utils.remove_empties(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/lacp.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/lacp.py new file mode 100644 index 00000000..5c80d30d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp/lacp.py @@ -0,0 +1,90 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr lacp fact class +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 copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lacp.lacp import ( + LacpArgs, +) + + +class LacpFacts(object): + """The iosxr lacp fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = LacpArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="lacp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for lacp + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + data = self.get_config(connection) + + obj = {} + if "lacp" in data: + lacp_obj = self.render_config(self.generated_spec, data) + if lacp_obj: + obj = lacp_obj + + ansible_facts["ansible_network_resources"].pop("lacp", None) + facts = {} + + params = utils.validate_config(self.argument_spec, {"config": obj}) + facts["lacp"] = utils.remove_empties(params["config"]) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + + system_priority = utils.parse_conf_arg(conf, "priority") + config["system"]["priority"] = int(system_priority) if system_priority else system_priority + config["system"]["mac"]["address"] = utils.parse_conf_arg(conf, "mac") + + return config diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py new file mode 100644 index 00000000..2e69f7a6 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lacp_interfaces/lacp_interfaces.py @@ -0,0 +1,120 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr lacp_interfaces fact class +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 + + +import re + +from copy import deepcopy + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lacp_interfaces.lacp_interfaces import ( + Lacp_interfacesArgs, +) + + +class Lacp_interfacesFacts(object): + """The iosxr lacp_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Lacp_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for lacp_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_config(connection) + interfaces = ("\n" + data).split("\ninterface ") + + objs = [] + for interface in interfaces: + obj = self.render_config(self.generated_spec, interface) + if obj: + objs.append(obj) + + ansible_facts["ansible_network_resources"].pop("lacp_interfaces", None) + facts = {} + if objs: + facts["lacp_interfaces"] = [] + params = utils.validate_config( + self.argument_spec, + {"config": objs}, + ) + for cfg in params["config"]: + facts["lacp_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + + match = re.search( + r"(GigabitEthernet|Bundle-Ether|TenGigE|FortyGigE|HundredGigE)(\S+)", + conf, + re.M, + ) + if match: + config["name"] = match.group(1) + match.group(2) + + temp = { + "churn_logging": "lacp churn logging", + "switchover_suppress_flaps": "lacp switchover suppress-flaps", + "collector_max_delay": "lacp collector-max-delay", + "period": "lacp period", + } + + for key, value in iteritems(temp): + config[key] = utils.parse_conf_arg(conf, value) + + for key in config["system"].keys(): + config["system"][key] = utils.parse_conf_arg( + conf, + "lacp system {0}".format(key), + ) + + return utils.remove_empties(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py new file mode 100644 index 00000000..14435c1f --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lag_interfaces/lag_interfaces.py @@ -0,0 +1,151 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr lag_interfaces fact class +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 + + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lag_interfaces.lag_interfaces import ( + Lag_interfacesArgs, +) + + +class Lag_interfacesFacts(object): + """The iosxr lag_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Lag_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for lag_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_config(connection) + interfaces = ("\n" + data).split("\ninterface ") + + objs = [] + + for interface in interfaces: + if interface.startswith("Bundle-Ether"): + obj = self.render_config( + self.generated_spec, + interface, + interfaces, + ) + if obj: + objs.append(obj) + + ansible_facts["ansible_network_resources"].pop("lag_interfaces", None) + facts = {} + + facts["lag_interfaces"] = [] + params = utils.validate_config(self.argument_spec, {"config": objs}) + for cfg in params["config"]: + facts["lag_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf, data): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + match = re.search(r"(Bundle-Ether)(\d+)", conf, re.M) + if match: + config["name"] = match.group(1) + match.group(2) + config["load_balancing_hash"] = utils.parse_conf_arg( + conf, + "bundle load-balancing hash", + ) + config["mode"] = utils.parse_conf_arg(conf, "lacp mode") + config["links"]["max_active"] = utils.parse_conf_arg( + conf, + "bundle maximum-active links", + ) + config["links"]["min_active"] = utils.parse_conf_arg( + conf, + "bundle minimum-active links", + ) + config["members"] = self.parse_members(match.group(2), data) + + return utils.remove_empties(config) + + def parse_members(self, bundle_id, interfaces): + """ + Renders a list of member interfaces for every bundle + present in running-config. + + :param bundle_id: The Bundle-Ether ID fetched from running-config + :param interfaces: Data of all interfaces present in running-config + :rtype: list + :returns: A list of member interfaces + """ + + def _parse_interface(name): + if name.startswith("preconfigure"): + return name.split()[1] + else: + return name.split()[0] + + members = [] + for interface in interfaces: + if not interface.startswith("Bu"): + match = re.search( + r"bundle id (\d+) mode (\S+)", + interface, + re.M, + ) + if match: + if bundle_id == match.group(1): + members.append( + { + "member": _parse_interface(interface), + "mode": match.group(2), + }, + ) + + return members diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py new file mode 100644 index 00000000..9e346d36 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The iosxr legacy fact class +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 + + +import platform +import re + +from ansible.module_utils.six import iteritems +from ansible.module_utils.six.moves import zip + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + get_capabilities, + run_commands, +) + + +class FactsBase(object): + + COMMANDS = frozenset() + + def __init__(self, module): + self.module = module + self.facts = dict() + self.warnings = list() + self.responses = None + + def populate(self): + self.responses = run_commands( + self.module, + list(self.COMMANDS), + check_rc=False, + ) + + +class Default(FactsBase): + def populate(self): + self.facts.update(self.platform_facts()) + + def platform_facts(self): + platform_facts = {} + + resp = get_capabilities(self.module) + device_info = resp["device_info"] + + platform_facts["system"] = device_info["network_os"] + + for item in ("model", "image", "version", "platform", "hostname"): + val = device_info.get("network_os_%s" % item) + if val: + platform_facts[item] = val + + platform_facts["api"] = resp["network_api"] + platform_facts["python_version"] = platform.python_version() + + return platform_facts + + +class Hardware(FactsBase): + + COMMANDS = ["dir /all", "show memory summary"] + + def populate(self): + super(Hardware, self).populate() + data = self.responses[0] + self.facts["filesystems"] = self.parse_filesystems(data) + + data = self.responses[1] + match = re.search(r"Physical Memory: (\d+)M total \((\d+)", data) + if match: + self.facts["memtotal_mb"] = match.group(1) + self.facts["memfree_mb"] = match.group(2) + + def parse_filesystems(self, data): + return re.findall(r"^Directory of (\S+)", data, re.M) + + +class Config(FactsBase): + + COMMANDS = ["show running-config"] + + def populate(self): + super(Config, self).populate() + self.facts["config"] = self.responses[0] + + +class Interfaces(FactsBase): + + COMMANDS = [ + "show interfaces", + "show ipv6 interface", + "show lldp", + "show lldp neighbors detail", + ] + + def populate(self): + super(Interfaces, self).populate() + self.facts["all_ipv4_addresses"] = list() + self.facts["all_ipv6_addresses"] = list() + + interfaces = self.parse_interfaces(self.responses[0]) + self.facts["interfaces"] = self.populate_interfaces(interfaces) + + data = self.responses[1] + if len(data) > 0: + data = self.parse_interfaces(data) + self.populate_ipv6_interfaces(data) + + if "LLDP is not enabled" not in self.responses[2]: + neighbors = self.responses[3] + self.facts["neighbors"] = self.parse_neighbors(neighbors) + + def populate_interfaces(self, interfaces): + facts = dict() + for key, value in iteritems(interfaces): + intf = dict() + intf["description"] = self.parse_description(value) + intf["macaddress"] = self.parse_macaddress(value) + + ipv4 = self.parse_ipv4(value) + intf["ipv4"] = self.parse_ipv4(value) + if ipv4: + self.add_ip_address(ipv4["address"], "ipv4") + + intf["mtu"] = self.parse_mtu(value) + intf["bandwidth"] = self.parse_bandwidth(value) + intf["duplex"] = self.parse_duplex(value) + intf["lineprotocol"] = self.parse_lineprotocol(value) + intf["operstatus"] = self.parse_operstatus(value) + intf["type"] = self.parse_type(value) + + facts[key] = intf + return facts + + def populate_ipv6_interfaces(self, data): + for key, value in iteritems(data): + if key in ["No", "RPF"] or key.startswith("IP"): + continue + self.facts["interfaces"][key]["ipv6"] = list() + addresses = re.findall(r"\s+(.+), subnet", value, re.M) + subnets = re.findall(r", subnet is (.+)$", value, re.M) + for addr, subnet in zip(addresses, subnets): + ipv6 = dict(address=addr.strip(), subnet=subnet.strip()) + self.add_ip_address(addr.strip(), "ipv6") + self.facts["interfaces"][key]["ipv6"].append(ipv6) + + def add_ip_address(self, address, family): + if family == "ipv4": + self.facts["all_ipv4_addresses"].append(address) + else: + self.facts["all_ipv6_addresses"].append(address) + + def parse_neighbors(self, neighbors): + facts = dict() + nbors = neighbors.split( + "------------------------------------------------", + ) + for entry in nbors[1:]: + if entry == "": + continue + intf = self.parse_lldp_intf(entry) + if intf not in facts: + facts[intf] = list() + fact = dict() + fact["host"] = self.parse_lldp_host(entry) + fact["remote_description"] = self.parse_lldp_remote_desc(entry) + fact["port"] = self.parse_lldp_port(entry) + facts[intf].append(fact) + return facts + + def parse_interfaces(self, data): + parsed = dict() + key = "" + for line in data.split("\n"): + if len(line) == 0: + continue + if line[0] == " ": + parsed[key] += "\n%s" % line + else: + match = re.match(r"^(\S+)", line) + if match: + key = match.group(1) + parsed[key] = line + return parsed + + def parse_description(self, data): + match = re.search(r"Description: (.+)$", data, re.M) + if match: + return match.group(1) + + def parse_macaddress(self, data): + match = re.search(r"address is (\S+)", data) + if match: + return match.group(1) + + def parse_ipv4(self, data): + match = re.search(r"Internet address is (\S+)/(\d+)", data) + if match: + addr = match.group(1) + masklen = int(match.group(2)) + return dict(address=addr, masklen=masklen) + + def parse_mtu(self, data): + match = re.search(r"MTU (\d+)", data) + if match: + return int(match.group(1)) + + def parse_bandwidth(self, data): + match = re.search(r"BW (\d+)", data) + if match: + return int(match.group(1)) + + def parse_duplex(self, data): + match = re.search(r"(\w+)(?: D|-d)uplex", data, re.M) + if match: + return match.group(1) + + def parse_type(self, data): + match = re.search(r"Hardware is (.+),", data, re.M) + if match: + return match.group(1) + + def parse_lineprotocol(self, data): + match = re.search(r"line protocol is (.+)\s+?$", data, re.M) + if match: + return match.group(1) + + def parse_operstatus(self, data): + match = re.search(r"^(?:.+) is (.+),", data, re.M) + if match: + return match.group(1) + + def parse_lldp_intf(self, data): + match = re.search(r"^Local Interface: (.+)$", data, re.M) + if match: + return match.group(1) + + def parse_lldp_remote_desc(self, data): + match = re.search(r"Port Description: (.+)$", data, re.M) + if match: + return match.group(1) + + def parse_lldp_host(self, data): + match = re.search(r"System Name: (.+)$", data, re.M) + if match: + return match.group(1) + + def parse_lldp_port(self, data): + match = re.search(r"Port id: (.+)$", data, re.M) + if match: + return match.group(1) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/lldp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/lldp_global.py new file mode 100644 index 00000000..ce17af21 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_global/lldp_global.py @@ -0,0 +1,106 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr lldp fact class +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 copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lldp_global.lldp_global import ( + Lldp_globalArgs, +) + + +class Lldp_globalFacts(object): + """The iosxr lldp fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Lldp_globalArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="lldp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for lldp + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + data = self.get_config(connection) + + obj = {} + if "lldp" in data: + lldp_obj = self.render_config(self.generated_spec, data) + if lldp_obj: + obj = lldp_obj + + ansible_facts["ansible_network_resources"].pop("lldp_global", None) + facts = {} + + params = utils.validate_config(self.argument_spec, {"config": obj}) + facts["lldp_global"] = utils.remove_empties(params["config"]) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + + for key in spec.keys(): + if key == "subinterfaces": + config[key] = True if "subinterfaces enable" in conf else None + + elif key == "tlv_select": + for item in [ + "system_name", + "port_description", + "management_address", + "system_description", + "system_capabilities", + ]: + config[key][item] = ( + False if ("{0} disable".format(item.replace("_", "-"))) in conf else None + ) + + else: + value = utils.parse_conf_arg(conf, key) + config[key] = int(value) if value else value + + return config diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000..f5e20c80 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,111 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr lldp_interfaces fact class +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 + + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lldp_interfaces.lldp_interfaces import ( + Lldp_interfacesArgs, +) + + +class Lldp_interfacesFacts(object): + """The iosxr lldp_interfaces fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Lldp_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_config(self, connection): + return connection.get_config(flags="interface") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for lldp_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_config(connection) + interfaces = ("\n" + data).split("\ninterface ") + + objs = [] + for interface in interfaces: + obj = self.render_config(self.generated_spec, interface) + if obj: + objs.append(obj) + + ansible_facts["ansible_network_resources"].pop("lldp_interfaces", None) + facts = {} + + if objs: + facts["lldp_interfaces"] = [] + params = utils.validate_config( + self.argument_spec, + {"config": objs}, + ) + for cfg in params["config"]: + facts["lldp_interfaces"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + + match = re.search( + r"(GigabitEthernet|Bundle-Ether|TenGigE|FortyGigE|HundredGigE)(\S+)", + conf, + re.M, + ) + if match: + config["name"] = match.group(1) + match.group(2) + + for key in ["receive", "transmit"]: + config[key] = False if ("{0} disable".format(key)) in conf else None + + for x in ["ieee-nearest-bridge", "ieee-nearest-non-tmpr-bridge"]: + if x in conf: + config["destination"]["mac_address"] = x + + return utils.remove_empties(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/logging_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/logging_global.py new file mode 100644 index 00000000..47c6c439 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/logging_global/logging_global.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr logging_global fact class +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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.logging_global.logging_global import ( + Logging_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.logging_global import ( + Logging_globalTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Logging_globalFacts(object): + """The iosxr logging_global facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Logging_globalArgs.argument_spec + + def get_config(self, connection): + return connection.get("show running-config logging") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Logging_global network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_config(connection) + + flatten_context_list = [ + "logging archive", + "logging tls-server", + "logging correlator rule", + "logging correlator ruleset", + "logging events filter", + "logging buffered discriminator", + "logging monitor discriminator", + "logging console discriminator", + ] + + for x in flatten_context_list: + data = flatten_config(data, x) + # parse native config using the Logging_global template + logging_global_parser = Logging_globalTemplate( + lines=data.splitlines(), + module=self._module, + ) + objs = logging_global_parser.parse() + objs["tls_servers"] = list(objs.get("tls_servers", {}).values()) + if objs.get("correlator"): + objs["correlator"]["rules"] = list( + objs.get("correlator", {}).get("rules", {}).values(), + ) + objs["correlator"]["rule_sets"] = list( + objs.get("correlator", {}).get("rule_sets", {}).values(), + ) + for i, x in enumerate(objs["correlator"]["rule_sets"]): + if None in x["rulename"]: + objs["correlator"]["rule_sets"][i]["rulename"].remove(None) + + ansible_facts["ansible_network_resources"].pop("logging_global", None) + + params = utils.remove_empties( + logging_global_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["logging_global"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/ntp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/ntp_global.py new file mode 100644 index 00000000..8cf69525 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ntp_global/ntp_global.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr ntp_global fact class +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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ntp_global.ntp_global import ( + Ntp_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ntp_global import ( + Ntp_globalTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Ntp_globalFacts(object): + """The iosxr ntp_global facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Ntp_globalArgs.argument_spec + + def get_config(self, connection): + return connection.get("show running-config ntp") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Ntp_global network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_config(connection) + + flatten_context_list = ["interface", "ntp"] + + for x in flatten_context_list: + data = flatten_config(data, x) + # parse native config using the Ntp_global template + ntp_global_parser = Ntp_globalTemplate( + lines=data.splitlines(), + module=self._module, + ) + objs = ntp_global_parser.parse() + if "access_group" in objs: + objs["access_group"]["vrfs"] = list( + objs.get("access_group", {}).get("vrfs", {}).values(), + ) + objs["access_group"]["vrfs"] = sorted( + objs["access_group"]["vrfs"], + key=lambda k: k["name"], + ) + if "interfaces" in objs: + objs["interfaces"] = list(objs.get("interfaces", {}).values()) + if "peers" in objs: + objs["peers"] = list(objs.get("peers", {}).values()) + if "servers" in objs: + objs["servers"] = list(objs.get("servers", {}).values()) + if "source_vrfs" in objs: + objs["source_vrfs"] = list(objs.get("source_vrfs", {}).values()) + + pkey = { + "authentication_keys": "id", + "peers": "peer", + "servers": "server", + "trusted_keys": "key_id", + "source_vrfs": "name", + "interfaces": "name", + } + + for x in pkey.keys(): + if x in objs: + objs[x] = sorted(objs[x], key=lambda k: k[pkey[x]]) + + ansible_facts["ansible_network_resources"].pop("ntp_global", None) + + params = utils.remove_empties( + ntp_global_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["ntp_global"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/ospf_interfaces.py new file mode 100644 index 00000000..7296f70a --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospf_interfaces/ospf_interfaces.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr ospf_interfaces fact class +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. +""" + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospf_interfaces.ospf_interfaces import ( + Ospf_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospf_interfaces import ( + Ospf_interfacesTemplate, +) + + +class Ospf_interfacesFacts(object): + """The iosxr ospf_interfaces facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Ospf_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_ospf_interfaces(self, connection, flag): + cmd = "show running-config router " + flag + return connection.get(cmd) + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Ospf_interfaces network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + if not data: + data = self.get_ospf_interfaces(connection, flag="ospf") + data += "\n" + self.get_ospf_interfaces(connection, flag="ospfv3") + end_flag, end_mark, count, v_read = 0, 0, 0, False + areas, config_commands = [], [] + area_str, process, curr_process = "", "", "" + data = data.splitlines() + + for line in data: + if line.startswith("router") and curr_process != "" and curr_process != line: + end_mark, count, end_flag, area_str = 0, 0, 0, "" + if end_mark == 0 and count == 0 and line.startswith("router ospf"): + curr_process = line + process = re.sub("\n", "", line) + count += 1 + config_commands.append(process) + else: + if line.startswith(" area") or line.startswith(" vrf"): + area_str = process + re.sub("\n", "", line) + config_commands.append(area_str.replace(" ", " ")) + end_flag += 1 + elif line.startswith(" interface"): + ospf_int = area_str + re.sub("\n", "", line) + # default output format has more spaces with default identation + # reset the spaces with replace + config_commands.append(ospf_int.replace(" ", " ")) + v_read = True + elif v_read: + if "!" not in line: + command = ospf_int.replace(" ", " ") + re.sub( + "\n", + "", + line, + ) + config_commands.append(command.replace(" ", " ")) + else: + v_read = False + elif end_flag > 0 and "!" not in line: + command = area_str + re.sub("\n", "", line) + config_commands.append(command.replace(" ", " ")) + elif "!" in line: + end_flag = 0 + end_mark += 1 + if end_mark == 3: + end_mark, count = 0, 0 + area_str = "" + else: + command = process + line + command.replace(" ", " ") + config_commands.append(re.sub("\n", "", command)) + areas.append(re.sub("\n", "", command)) + data = config_commands + + ospf_interfaces_parser = Ospf_interfacesTemplate( + lines=data, + module=self._module, + ) + objs = list(ospf_interfaces_parser.parse().values()) + if objs: + for item in objs: + item["address_family"] = list(item["address_family"].values()) + for af in item["address_family"]: + if af.get("processes"): + af["processes"] = list(af["processes"].values()) + + ansible_facts["ansible_network_resources"].pop("ospf_interfaces", None) + + params = utils.remove_empties( + ospf_interfaces_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["ospf_interfaces"] = params.get("config", []) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/ospfv2.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/ospfv2.py new file mode 100644 index 00000000..240ecb4d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv2/ospfv2.py @@ -0,0 +1,165 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr snmp fact class +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 + +import re + +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.network_template import ( + NetworkTemplate, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospfv2.ospfv2 import ( + Ospfv2Args, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospfv2 import ( + Ospfv2Template, +) + + +class Ospfv2Facts(object): + """The iosxr snmp fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Ospfv2Args.argument_spec + + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_ospfv2_data(self, connection): + return connection.get("show running-config router ospf") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_ospfv2_data(connection) + end_flag, end_mark, count, v_read = 0, 0, 0, False + areas, config_commands = [], [] + area_str, process, curr_process = "", "", "" + data = data.splitlines() + for line in data: + if line.startswith("router ospf") and curr_process != "" and curr_process != line: + end_mark, count, end_flag, area_str = 0, 0, 0, "" + if end_mark == 0 and count == 0 and line.startswith("router ospf"): + curr_process = line + process = re.sub("\n", "", line) + count += 1 + config_commands.append(process) + else: + if line.startswith(" area") or line.startswith(" vrf"): + area_str = process + re.sub("\n", "", line) + config_commands.append(area_str.replace(" ", " ")) + end_flag += 1 + elif line.startswith(" virtual-link"): + virtual_str = area_str + re.sub("\n", "", line) + config_commands.append(virtual_str.replace(" ", " ")) + v_read = True + elif v_read: + if "!" not in line: + command = virtual_str.replace(" ", " ") + re.sub( + "\n", + "", + line, + ) + config_commands.append(command.replace(" ", " ")) + else: + v_read = False + elif end_flag > 0 and "!" not in line: + command = area_str + re.sub("\n", "", line) + config_commands.append(command.replace(" ", " ")) + elif "!" in line: + end_flag = 0 + end_mark += 1 + if end_mark == 3: + end_mark, count = 0, 0 + area_str = "" + else: + command = process + line + command.replace(" ", " ") + config_commands.append(re.sub("\n", "", command)) + areas.append(re.sub("\n", "", command)) + data = config_commands + ipv4 = {"processes": []} + rmmod = NetworkTemplate( + lines=data, + tmplt=Ospfv2Template(), + module=self._module, + ) + current = rmmod.parse() + + # convert some of the dicts to lists + for key, sortv in [("processes", "process_id")]: + if key in current and current[key]: + current[key] = current[key].values() + current[key] = sorted( + current[key], + key=lambda k, sk=sortv: k[sk], + ) + + for process in current.get("processes", []): + if "areas" in process: + process["areas"] = list(process["areas"].values()) + process["areas"] = sorted( + process["areas"], + key=lambda k, sk="area_id": k[sk], + ) + for area in process["areas"]: + if "ranges" in area: + area["ranges"] = sorted( + area["ranges"], + key=lambda k, s="ranges": k[s], + ) + if "virtual_link" in area: + area["virtual_link"] = list( + area["virtual_link"].values(), + ) + area["virtual_link"] = sorted( + area["virtual_link"], + key=lambda k, sk="id": k[sk], + ) + ipv4["processes"].append(process) + + ansible_facts["ansible_network_resources"].pop("ospfv2", None) + facts = {} + if current: + params = rmmod.validate_config( + self.argument_spec, + {"config": ipv4}, + redact=True, + ) + params = utils.remove_empties(params) + + facts["ospfv2"] = params["config"] + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/ospfv3.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/ospfv3.py new file mode 100644 index 00000000..49302ce9 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/ospfv3/ospfv3.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import re + +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.network_template import ( + NetworkTemplate, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospfv3.ospfv3 import ( + Ospfv3Args, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.ospfv3 import ( + Ospfv3Template, +) + + +class Ospfv3Facts(object): + """The iosxr snmp fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Ospfv3Args.argument_spec + + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_ospfv3_data(self, connection): + return connection.get("show running-config router ospfv3") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + + if not data: + data = self.get_ospfv3_data(connection) + end_flag, end_mark, count, v_read = 0, 0, 0, False + areas, config_commands = [], [] + area_str, process, curr_process = "", "", "" + data = data.splitlines() + for line in data: + if line.startswith("router ospfv3") and curr_process != "" and curr_process != line: + end_mark, count, end_flag, area_str = 0, 0, 0, "" + if end_mark == 0 and count == 0 and line.startswith("router ospfv3"): + curr_process = line + process = re.sub("\n", "", line) + count += 1 + config_commands.append(process) + else: + if line.startswith(" area") or line.startswith(" vrf"): + area_str = process + re.sub("\n", "", line) + config_commands.append(area_str.replace(" ", " ")) + end_flag += 1 + elif line.startswith(" virtual-link"): + virtual_str = area_str + re.sub("\n", "", line) + config_commands.append(virtual_str.replace(" ", " ")) + v_read = True + elif v_read: + if "!" not in line: + command = virtual_str.replace(" ", " ") + re.sub( + "\n", + "", + line, + ) + config_commands.append(command.replace(" ", " ")) + else: + v_read = False + elif end_flag > 0 and "!" not in line: + command = area_str + re.sub("\n", "", line) + config_commands.append(command.replace(" ", " ")) + elif "!" in line: + end_flag = 0 + end_mark += 1 + if end_mark == 3: + end_mark, count = 0, 0 + area_str = "" + else: + command = process + line + command.replace(" ", " ") + config_commands.append(re.sub("\n", "", command)) + areas.append(re.sub("\n", "", command)) + data = config_commands + ipv4 = {"processes": []} + rmmod = NetworkTemplate( + lines=data, + tmplt=Ospfv3Template(), + module=self._module, + ) + current = rmmod.parse() + + # convert some of the dicts to lists + for key, sortv in [("processes", "process_id")]: + if key in current and current[key]: + current[key] = current[key].values() + current[key] = sorted( + current[key], + key=lambda k, sk=sortv: k[sk], + ) + + for process in current.get("processes", []): + if "areas" in process: + process["areas"] = list(process["areas"].values()) + process["areas"] = sorted( + process["areas"], + key=lambda k, sk="area_id": k[sk], + ) + for area in process["areas"]: + if "ranges" in area: + area["ranges"] = sorted( + area["ranges"], + key=lambda k, s="ranges": k[s], + ) + if "virtual_link" in area: + area["virtual_link"] = list( + area["virtual_link"].values(), + ) + area["virtual_link"] = sorted( + area["virtual_link"], + key=lambda k, sk="id": k[sk], + ) + ipv4["processes"].append(process) + + ansible_facts["ansible_network_resources"].pop("ospfv3", None) + facts = {} + if current: + params = rmmod.validate_config( + self.argument_spec, + {"config": ipv4}, + redact=True, + ) + params = utils.remove_empties(params) + + facts["ospfv3"] = params["config"] + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/prefix_lists.py new file mode 100644 index 00000000..3bf66576 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/prefix_lists/prefix_lists.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr prefix_lists fact class +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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.prefix_lists.prefix_lists import ( + Prefix_listsArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.prefix_lists import ( + Prefix_listsTemplate, +) + + +class Prefix_listsFacts(object): + """The iosxr prefix_lists facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Prefix_listsArgs.argument_spec + + def get_config(self, connection): + return connection.get("show running-config") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Prefix_lists network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + if not data: + data = self.get_config(connection) + + # parse native config using the Prefix_lists template + prefix_lists_parser = Prefix_listsTemplate( + lines=data.splitlines(), + module=self._module, + ) + objs = list(prefix_lists_parser.parse().values()) + + if objs: + for item in objs: + item["prefix_lists"] = list(item["prefix_lists"].values()) + + ansible_facts["ansible_network_resources"].pop("prefix_lists", None) + + params = utils.remove_empties( + prefix_lists_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["prefix_lists"] = params.get("config", []) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/snmp_server.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/snmp_server.py new file mode 100644 index 00000000..a631b35c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/snmp_server/snmp_server.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The iosxr snmp_server fact class +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 ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.snmp_server.snmp_server import ( + Snmp_serverArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.rm_templates.snmp_server import ( + Snmp_serverTemplate, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import ( + flatten_config, +) + + +class Snmp_serverFacts(object): + """The iosxr snmp_server facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Snmp_serverArgs.argument_spec + + def get_config(self, connection): + return connection.get("show running-config snmp-server") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Snmp_server network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_config(connection) + + flatten_context_list = [ + "snmp-server vrf", + "snmp-server mib bulkstat schema", + "snmp-server mib bulkstat transfer-id", + "snmp-server correlator rule", + "snmp-server interface", + "snmp-server correlator rule", + "snmp-server correlator ruleset", + ] + + for x in flatten_context_list: + data = flatten_config(data, x) + # parse native config using the Snmp_server template + snmp_server_parser = Snmp_serverTemplate( + lines=data.splitlines(), + module=self._module, + ) + objs = snmp_server_parser.parse() + + dict_to_list = [ + "context", + "mib_object_lists", + "mib_schema", + "mib_bulkstat_transfer_ids", + "vrfs", + "interfaces", + ] + for i in dict_to_list: + if i in objs: + objs[i] = list(objs[i].values()) + if i == "vrfs": + for j in objs[i]: + j["hosts"].remove({}) + j["context"] = list(j["context"].values()) + + ansible_facts["ansible_network_resources"].pop("snmp_server", None) + + params = utils.remove_empties( + snmp_server_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + facts["snmp_server"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/static_routes.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/static_routes.py new file mode 100644 index 00000000..e6e37482 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/static_routes/static_routes.py @@ -0,0 +1,196 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The iosxr static_routes fact class +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 + + +import re + +from copy import deepcopy + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.static_routes.static_routes import ( + Static_routesArgs, +) + + +class Static_routesFacts(object): + """The iosxr static_routes fact class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Static_routesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def get_device_data(self, connection): + return connection.get_config(flags="router static") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for static_routes + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + data = self.get_device_data(connection) + + objs = [] + + if "No such configuration" not in data: + for entry in re.compile(r"(\s) vrf").split(data): + obj = self.render_config(self.generated_spec, entry) + if obj: + objs.append(obj) + + ansible_facts["ansible_network_resources"].pop("static_routes", None) + facts = {} + + facts["static_routes"] = [] + params = utils.validate_config(self.argument_spec, {"config": objs}) + for cfg in params["config"]: + facts["static_routes"].append(utils.remove_empties(cfg)) + + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + entry_list = conf.split(" address-family") + config["address_families"] = [] + + if "router static" not in entry_list[0]: + config["vrf"] = entry_list[0].replace("!", "").strip() + + for item in entry_list[1:]: + routes = [] + address_family = {"routes": []} + address_family["afi"], address_family["safi"] = self.parse_af(item) + + destinations = re.findall(r"((?:\S+)/(?:\d+)) (?:.*)", item, re.M) + for dest in set(destinations): + route = {"next_hops": []} + route["dest"] = dest + + regex = r"%s .+$" % dest + cfg = re.findall(regex, item, re.M) + + for route_entry in cfg: + exit_point = {} + exit_point["forward_router_address"] = self.parse_faddr( + route_entry, + ) + exit_point["interface"] = self.parse_intf(route_entry) + exit_point["admin_distance"] = self.parse_admin_distance( + route_entry, + ) + + for x in [ + "tag", + "tunnel-id", + "metric", + "description", + "track", + "vrflabel", + "dest_vrf", + ]: + exit_point[x.replace("-", "_")] = self.parse_attrib( + route_entry, + x.replace("dest_vrf", "vrf"), + ) + + route["next_hops"].append(exit_point) + + routes.append(route) + address_family["routes"] = sorted( + routes, + key=lambda i: i["dest"], + ) + config["address_families"].append(address_family) + + return utils.remove_empties(config) + + def parse_af(self, item): + match = re.search(r"(?:\s*)(\w+)(?:\s*)(\w+)", item, re.M) + if match: + return match.group(1), match.group(2) + + def parse_faddr(self, item): + for x in item.split(" "): + if (":" in x or "." in x) and "/" not in x: + return x + + def parse_intf(self, item): + inf_search_strs = [ + r" ((\w+)((?:\d)/(?:\d)/(?:\d)/(?:\d+)))", + r" (([a-zA-Z]+)(?:\d+))", + ] + for i in inf_search_strs: + match = re.search(i, item, re.M) + if match: + return match.group(1) + + def parse_attrib(self, item, attrib): + match = re.search(r" %s (\S+)" % attrib, item) + if match: + val = match.group(1).strip("'") + if attrib in ["tunnel-id", "vrflabel", "tag", "metric"]: + val = int(val) + return val + + def parse_admin_distance(self, item): + split_item = item.split(" ") + for item in [ + "vrf", + "metric", + "tunnel-id", + "vrflabel", + "track", + "tag", + "description", + ]: + try: + del split_item[split_item.index(item) + 1] + del split_item[split_item.index(item)] + except ValueError: + continue + try: + return [ + i + for i in split_item + if "." not in i and ":" not in i and ord(i[0]) > 48 and ord(i[0]) < 57 + ][0] + except IndexError: + return None diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/iosxr.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/iosxr.py new file mode 100644 index 00000000..ea15fdfc --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/iosxr.py @@ -0,0 +1,588 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# Copyright (c) 2015 Peter Sprygada, <psprygada@ansible.com> +# Copyright (c) 2017 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import json +import re + +from difflib import Differ + +from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.basic import env_fallback +from ansible.module_utils.connection import Connection, ConnectionError +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import ( + NetconfConnection, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + + +try: + from ncclient.xml_ import to_xml + + HAS_NCCLIENT = True +except ImportError: + HAS_NCCLIENT = False + +try: + from lxml import etree + + HAS_XML = True +except ImportError: + HAS_XML = False + +_EDIT_OPS = frozenset(["merge", "create", "replace", "delete"]) + +BASE_1_0 = "{urn:ietf:params:xml:ns:netconf:base:1.0}" + +NS_DICT = { + "BASE_NSMAP": {"xc": "urn:ietf:params:xml:ns:netconf:base:1.0"}, + "BANNERS_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg"}, + "INTERFACES_NSMAP": {None: "http://openconfig.net/yang/interfaces"}, + "INSTALL_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-spirit-install-instmgr-oper"}, + "INSTALL_OLD_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-installmgr-admin-oper"}, + "HOST-NAMES_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-shellutil-cfg"}, + "M:TYPE_NSMAP": {"idx": "urn:ietf:params:xml:ns:yang:iana-if-type"}, + "ETHERNET_NSMAP": {None: "http://openconfig.net/yang/interfaces/ethernet"}, + "CETHERNET_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-drivers-media-eth-cfg"}, + "INTERFACE-CONFIGURATIONS_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg"}, + "INFRA-STATISTICS_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-statsd-oper"}, + "INTERFACE-PROPERTIES_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-oper"}, + "IP-DOMAIN_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-ip-domain-cfg"}, + "SYSLOG_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-infra-syslog-cfg"}, + "AAA_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg"}, + "AAA_LOCALD_NSMAP": {None: "http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-cfg"}, +} + + +command_spec = {"command": dict(), "prompt": dict(default=None), "answer": dict(default=None)} + +CONFIG_MISPLACED_CHILDREN = [re.compile(r"^end-\s*(.+)$")] + +# Objects defined in Route-policy Language guide of IOS_XR. +# Reconfiguring these objects replace existing configurations. +# Hence these objects should be played direcly from candidate +# configurations +CONFIG_BLOCKS_FORCED_IN_DIFF = [ + {"start": re.compile(r"^route-policy"), "end": re.compile(r"end-policy$")}, + {"start": re.compile(r"^prefix-set"), "end": re.compile(r"end-set$")}, + {"start": re.compile(r"^as-path-set"), "end": re.compile(r"end-set$")}, + {"start": re.compile(r"^community-set"), "end": re.compile(r"end-set$")}, + {"start": re.compile(r"^rd-set"), "end": re.compile(r"end-set$")}, + {"start": re.compile(r"^extcommunity-set"), "end": re.compile(r"end-set$")}, +] + + +def get_connection(module): + if hasattr(module, "connection"): + return module.connection + + capabilities = get_capabilities(module) + network_api = capabilities.get("network_api") + if network_api in ["cliconf", "ansible.netcommon.grpc"]: + module.connection = Connection(module._socket_path) + elif network_api == "netconf": + module.connection = NetconfConnection(module._socket_path) + else: + module.fail_json(msg="Invalid connection type {0!s}".format(network_api)) + + return module.connection + + +def get_capabilities(module): + if hasattr(module, "capabilities"): + return module.capabilities + try: + capabilities = Connection(module._socket_path).get_capabilities() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + module.capabilities = json.loads(capabilities) + + return module.capabilities + + +def build_xml_subtree(container_ele, xmap, param=None, opcode=None): + sub_root = container_ele + meta_subtree = list() + + for key, meta in xmap.items(): + candidates = meta.get("xpath", "").split("/") + if container_ele.tag == candidates[-2]: + parent = container_ele + elif sub_root.tag == candidates[-2]: + parent = sub_root + else: + parent = sub_root.find( + ".//" + meta.get("xpath", "").split(sub_root.tag + "/", 1)[1].rsplit("/", 1)[0], + ) + + if ( + opcode in ("delete", "merge") and meta.get("operation", "unknown") == "edit" + ) or meta.get("operation", None) is None: + + if meta.get("tag", False) is True: + if parent.tag == container_ele.tag: + if meta.get("ns", False) is True: + child = etree.Element(candidates[-1], nsmap=NS_DICT[key.upper() + "_NSMAP"]) + else: + child = etree.Element(candidates[-1]) + meta_subtree.append(child) + sub_root = child + else: + if meta.get("ns", False) is True: + child = etree.SubElement( + parent, + candidates[-1], + nsmap=NS_DICT[key.upper() + "_NSMAP"], + ) + else: + child = etree.SubElement(parent, candidates[-1]) + + if meta.get("attrib", None) is not None and opcode in ("delete", "merge"): + child.set(BASE_1_0 + meta.get("attrib"), opcode) + + continue + + text = None + param_key = key.split(":") + if param_key[0] == "a": + if param is not None and param.get(param_key[1], None) is not None: + text = param.get(param_key[1]) + elif param_key[0] == "m": + if meta.get("value", None) is not None: + text = meta.get("value") + + if text: + if meta.get("ns", False) is True: + child = etree.SubElement( + parent, + candidates[-1], + nsmap=NS_DICT[key.upper() + "_NSMAP"], + ) + else: + child = etree.SubElement(parent, candidates[-1]) + child.text = text + + if meta.get("attrib", None) is not None and opcode in ("delete", "merge"): + child.set(BASE_1_0 + meta.get("attrib"), opcode) + + if len(meta_subtree) > 1: + for item in meta_subtree: + container_ele.append(item) + + if sub_root == container_ele: + return None + else: + return sub_root + + +def build_xml(container, xmap=None, params=None, opcode=None, namespace=None): + """ + Builds netconf xml rpc document from meta-data + + Args: + container: the YANG container within the namespace + xmap: meta-data map to build xml tree + params: Input params that feed xml tree values + opcode: operation to be performed (merge, delete etc.) + + Example: + Module inputs: + banner_params = [{'banner':'motd', 'text':'Ansible banner example', 'state':'present'}] + + Meta-data definition: + bannermap = collections.OrderedDict() + bannermap.update([ + ('banner', {'xpath' : 'banners/banner', 'tag' : True, 'attrib' : "operation"}), + ('a:banner', {'xpath' : 'banner/banner-name'}), + ('a:text', {'xpath' : 'banner/banner-text', 'operation' : 'edit'}) + ]) + + Fields: + key: exact match to the key in arg_spec for a parameter + (prefixes --> a: value fetched from arg_spec, m: value fetched from meta-data) + xpath: xpath of the element (based on YANG model) + tag: True if no text on the element + attrib: attribute to be embedded in the element (e.g. xc:operation="merge") + operation: if edit --> includes the element in edit_config() query else ignores for get() queries + value: if key is prefixed with "m:", value is required in meta-data + + Output: + <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <banners xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg"> + <banner xc:operation="merge"> + <banner-name>motd</banner-name> + <banner-text>Ansible banner example</banner-text> + </banner> + </banners> + </config> + :returns: xml rpc document as a string + """ + if not namespace: + namespace = container + if opcode == "filter": + root = etree.Element("filter", type="subtree") + elif opcode in ("delete", "merge"): + root = etree.Element("config", nsmap=NS_DICT["BASE_NSMAP"]) + + container_ele = etree.SubElement(root, container, nsmap=NS_DICT[namespace.upper() + "_NSMAP"]) + + if xmap is not None: + if params is None: + build_xml_subtree(container_ele, xmap, opcode=opcode) + else: + subtree_list = list() + for param in to_list(params): + subtree_ele = build_xml_subtree(container_ele, xmap, param=param, opcode=opcode) + if subtree_ele is not None: + subtree_list.append(subtree_ele) + + for item in subtree_list: + container_ele.append(item) + + return etree.tostring(root, encoding="unicode") + + +def etree_find(root, node): + try: + root = etree.fromstring(to_bytes(root)) + except (ValueError, etree.XMLSyntaxError): + pass + + return root.find(".//%s" % node.strip()) + + +def etree_findall(root, node): + try: + root = etree.fromstring(to_bytes(root)) + except (ValueError, etree.XMLSyntaxError): + pass + + return root.findall(".//%s" % node.strip()) + + +def is_cliconf(module): + capabilities = get_capabilities(module) + return capabilities.get("network_api") == "cliconf" + + +def is_netconf(module): + capabilities = get_capabilities(module) + network_api = capabilities.get("network_api") + if network_api == "netconf": + if not HAS_NCCLIENT: + module.fail_json(msg="ncclient is not installed") + if not HAS_XML: + module.fail_json(msg="lxml is not installed") + return True + + return False + + +def get_config_diff(module, running=None, candidate=None): + conn = get_connection(module) + + if is_cliconf(module): + try: + response = conn.get("show commit changes diff") + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + return response + elif is_netconf(module): + if running and candidate: + # ignore rpc-reply root node and diff from data element onwards + running_data_ele = etree.fromstring(to_bytes(running.strip())).getchildren()[0] + candidate_data_ele = etree.fromstring(to_bytes(candidate.strip())).getchildren()[0] + + running_data = to_text(etree.tostring(running_data_ele)).strip() + candidate_data = to_text(etree.tostring(candidate_data_ele)).strip() + if running_data != candidate_data: + d = Differ() + diff = list(d.compare(running_data.splitlines(), candidate_data.splitlines())) + return "\n".join(diff).strip() + + return None + + +def discard_config(module): + conn = get_connection(module) + try: + if is_netconf(module): + conn.discard_changes(remove_ns=True) + else: + conn.discard_changes() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + +def commit_config( + module, + comment=None, + confirmed=False, + confirm_timeout=None, + persist=False, + check=False, + label=None, +): + conn = get_connection(module) + reply = None + try: + if is_netconf(module): + if check: + reply = conn.validate(remove_ns=True) + else: + reply = conn.commit( + confirmed=confirmed, + timeout=confirm_timeout, + persist=persist, + remove_ns=True, + ) + elif is_cliconf(module): + if check: + module.fail_json( + msg="Validate configuration is not supported with network_cli connection type", + ) + else: + reply = conn.commit(comment=comment, label=label) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + return reply + + +def get_oper(module, filter=None): + conn = get_connection(module) + + if filter is not None: + try: + if is_netconf(module): + response = conn.get(filter=filter, remove_ns=True) + else: + response = conn.get(filter) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + else: + return None + + return to_bytes(etree.tostring(response), errors="surrogate_then_replace").strip() + + +def get_config(module, config_filter=None, source="running"): + conn = get_connection(module) + + # Note: Does not cache config in favour of latest config on every get operation. + try: + if is_netconf(module): + out = to_xml(conn.get_config(source=source, filter=config_filter, remove_ns=True)) + elif is_cliconf(module): + out = conn.get_config(source=source, flags=config_filter) + cfg = out.strip() + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + return cfg + + +def check_existing_commit_labels(conn, label): + out = conn.get(command="show configuration history detail | include %s" % label) + label_exist = re.search(label, out, re.M) + if label_exist: + return True + else: + return False + + +def load_config( + module, + command_filter, + commit=False, + replace=False, + comment=None, + admin=False, + exclusive=False, + running=None, + nc_get_filter=None, + label=None, +): + + conn = get_connection(module) + + diff = None + if is_netconf(module): + # FIXME: check for platform behaviour and restore this + # conn.lock(target = 'candidate') + # conn.discard_changes() + + try: + for filter in to_list(command_filter): + conn.edit_config(config=filter, remove_ns=True) + + candidate = get_config(module, source="candidate", config_filter=nc_get_filter) + diff = get_config_diff(module, running, candidate) + + if commit and diff: + commit_config(module) + else: + discard_config(module) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + finally: + # conn.unlock(target = 'candidate') + pass + + elif is_cliconf(module): + try: + if label: + old_label = check_existing_commit_labels(conn, label) + if old_label: + module.fail_json( + msg="commit label {%s} is already used for" + " an earlier commit, please choose a different label" + " and rerun task" % label, + ) + + response = conn.edit_config( + candidate=command_filter, + commit=commit, + admin=admin, + exclusive=exclusive, + replace=replace, + comment=comment, + label=label, + ) + if module._diff: + diff = response.get("diff") + + # Overwrite the default diff by the IOS XR commit diff. + # See plugins/cliconf/iosxr.py for this key set: show_commit_config_diff + diff = response.get("show_commit_config_diff") + + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + return diff + + +def run_commands(module, commands, check_rc=True): + connection = get_connection(module) + try: + return connection.run_commands(commands=commands, check_rc=check_rc) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc)) + + +def copy_file(module, src, dst, proto="scp"): + conn = get_connection(module) + try: + conn.copy_file(source=src, destination=dst, proto=proto) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + +def get_file(module, src, dst, proto="scp"): + conn = get_connection(module) + try: + conn.get_file(source=src, destination=dst, proto=proto) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + +# A list of commands like {end-set, end-policy, ...} are part of configuration +# block like { prefix-set, as-path-set , ... } but they are not indented properly +# to be included with their parent. sanitize_config will add indentation to +# end-* commands so they are included with their parents +def sanitize_config(config, force_diff_prefix=None): + conf_lines = config.split("\n") + for regex in CONFIG_MISPLACED_CHILDREN: + for index, line in enumerate(conf_lines): + m = regex.search(line) + if m and m.group(0): + if force_diff_prefix: + conf_lines[index] = " " + m.group(0) + force_diff_prefix + else: + conf_lines[index] = " " + m.group(0) + conf = ("\n").join(conf_lines) + return conf + + +def mask_config_blocks_from_diff(config, candidate, force_diff_prefix): + conf_lines = config.split("\n") + candidate_lines = candidate.split("\n") + + for regex in CONFIG_BLOCKS_FORCED_IN_DIFF: + block_index_start_end = [] + start_index = None + for index, line in enumerate(candidate_lines): + startre = regex["start"].search(line) + if startre and startre.group(0): + start_index = index + else: + endre = regex["end"].search(line) + if endre and endre.group(0) and start_index: + end_index = index + new_block = True + for prev_start, prev_end in block_index_start_end: + if start_index == prev_start: + # This might be end-set of another regex + # otherwise we would be having new start + new_block = False + break + if new_block and end_index: + block_index_start_end.append((start_index, end_index)) + + for start, end in block_index_start_end: + diff = False + if candidate_lines[start] in conf_lines: + run_conf_start_index = conf_lines.index(candidate_lines[start]) + else: + diff = False + continue + for i in range(start, end + 1): + if conf_lines[run_conf_start_index] == candidate_lines[i]: + run_conf_start_index = run_conf_start_index + 1 + else: + diff = True + break + if diff: + run_conf_start_index = conf_lines.index(candidate_lines[start]) + for i in range(start, end + 1): + conf_lines[run_conf_start_index] = ( + conf_lines[run_conf_start_index] + force_diff_prefix + ) + run_conf_start_index = run_conf_start_index + 1 + + conf = ("\n").join(conf_lines) + return conf + + +def get_os_version(module): + connection = get_connection(module) + if connection.get_device_info(): + os_version = connection.get_device_info()["network_os_version"] + return os_version diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py new file mode 100644 index 00000000..0d539340 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/address_family.py @@ -0,0 +1,133 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers import ( + CliProvider, +) + + +class AddressFamily(CliProvider): + def render(self, config=None): + commands = list() + safe_list = list() + + router_context = "router bgp %s" % self.get_value("config.bgp_as") + context_config = None + + for item in self.get_value("config.address_family"): + context = "address-family %s %s" % (item["afi"], item["safi"]) + context_commands = list() + + if config: + context_path = [router_context, context] + context_config = self.get_config_context( + config, + context_path, + indent=1, + ) + + for key, value in iteritems(item): + if value is not None: + meth = getattr(self, "_render_%s" % key, None) + if meth: + resp = meth(item, context_config) + if resp: + context_commands.extend(to_list(resp)) + + if context_commands: + commands.append(context) + commands.extend(context_commands) + commands.append("exit") + + safe_list.append(context) + + if config: + resp = self._negate_config(config, safe_list) + commands.extend(resp) + + return commands + + def _negate_config(self, config, safe_list=None): + commands = list() + matches = re.findall(r"(address-family .+)$", config, re.M) + for item in set(matches).difference(safe_list): + commands.append("no %s" % item) + return commands + + def _render_networks(self, item, config=None): + commands = list() + safe_list = list() + + for entry in item["networks"]: + network = entry["prefix"] + if entry["masklen"]: + network = "%s/%s" % (entry["prefix"], entry["masklen"]) + safe_list.append(network) + + cmd = "network %s" % network + + if entry["route_map"]: + cmd += " route-policy %s" % entry["route_map"] + + if not config or cmd not in config: + commands.append(cmd) + + if config and self.params["operation"] == "replace": + matches = re.findall(r"network (\S+)", config, re.M) + for entry in set(matches).difference(safe_list): + commands.append("no network %s" % entry) + + return commands + + def _render_redistribute(self, item, config=None): + commands = list() + safe_list = list() + + for entry in item["redistribute"]: + option = entry["protocol"] + + cmd = "redistribute %s" % entry["protocol"] + + if entry["id"] and entry["protocol"] in ( + "ospf", + "eigrp", + "isis", + "ospfv3", + ): + cmd += " %s" % entry["id"] + option += " %s" % entry["id"] + + if entry["metric"]: + cmd += " metric %s" % entry["metric"] + + if entry["route_map"]: + cmd += " route-policy %s" % entry["route_map"] + + if not config or cmd not in config: + commands.append(cmd) + + safe_list.append(option) + + if self.params["operation"] == "replace": + if config: + matches = re.findall( + r"redistribute (\S+)(?:\s*)(\d*)", + config, + re.M, + ) + for i in range(0, len(matches)): + matches[i] = " ".join(matches[i]).strip() + for entry in set(matches).difference(safe_list): + commands.append("no redistribute %s" % entry) + + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py new file mode 100644 index 00000000..29e4a1d2 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/neighbors.py @@ -0,0 +1,136 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re +import socket + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers import ( + CliProvider, +) + + +class Neighbors(CliProvider): + def render(self, config=None): + commands = list() + safe_list = list() + + router_context = "router bgp %s" % self.get_value("config.bgp_as") + context_config = None + + for item in self.get_value("config.neighbors"): + context_commands = list() + + neighbor = item["neighbor"] + + try: + socket.inet_aton(neighbor) + context = "neighbor %s" % neighbor + except socket.error: + context = "neighbor-group %s" % neighbor + + if config: + context_path = [router_context, context] + context_config = self.get_config_context( + config, + context_path, + indent=1, + ) + + for key, value in iteritems(item): + if value is not None: + meth = getattr(self, "_render_%s" % key, None) + if meth: + resp = meth(item, context_config) + if resp: + context_commands.extend(to_list(resp)) + + if context_commands: + commands.append(context) + commands.extend(context_commands) + commands.append("exit") + + safe_list.append(context) + + if config and safe_list: + commands.extend(self._negate_config(config, safe_list)) + + return commands + + def _negate_config(self, config, safe_list=None): + commands = list() + matches = re.findall(r"(neighbor \S+)", config, re.M) + for item in set(matches).difference(safe_list): + commands.append("no %s" % item) + return commands + + def _render_remote_as(self, item, config=None): + cmd = "remote-as %s" % item["remote_as"] + if not config or cmd not in config: + return cmd + + def _render_description(self, item, config=None): + cmd = "description %s" % item["description"] + if not config or cmd not in config: + return cmd + + def _render_enabled(self, item, config=None): + cmd = "shutdown" + if item["enabled"] is True: + cmd = "no %s" % cmd + if not config or cmd not in config: + return cmd + + def _render_update_source(self, item, config=None): + cmd = "update-source %s" % item["update_source"].replace(" ", "") + if not config or cmd not in config: + return cmd + + def _render_password(self, item, config=None): + cmd = "password %s" % item["password"] + if not config or cmd not in config: + return cmd + + def _render_ebgp_multihop(self, item, config=None): + cmd = "ebgp-multihop %s" % item["ebgp_multihop"] + if not config or cmd not in config: + return cmd + + def _render_tcp_mss(self, item, config=None): + cmd = "tcp mss %s" % item["tcp_mss"] + if not config or cmd not in config: + return cmd + + def _render_advertisement_interval(self, item, config=None): + cmd = "advertisement-interval %s" % item["advertisement_interval"] + if not config or cmd not in config: + return cmd + + def _render_neighbor_group(self, item, config=None): + cmd = "use neighbor-group %s" % item["neighbor_group"] + if not config or cmd not in config: + return cmd + + def _render_timers(self, item, config): + """generate bgp timer related configuration""" + keepalive = item["timers"]["keepalive"] + holdtime = item["timers"]["holdtime"] + min_neighbor_holdtime = item["timers"]["min_neighbor_holdtime"] + + if keepalive and holdtime: + cmd = "timers %s %s" % (keepalive, holdtime) + if min_neighbor_holdtime: + cmd += " %s" % min_neighbor_holdtime + if not config or cmd not in config: + return cmd + else: + raise ValueError( + "required both options for timers: keepalive and holdtime", + ) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/process.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/process.py new file mode 100644 index 00000000..bd2c08ae --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/cli/config/bgp/process.py @@ -0,0 +1,121 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.cli.config.bgp.address_family import ( + AddressFamily, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.cli.config.bgp.neighbors import ( + Neighbors, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers import ( + CliProvider, + register_provider, +) + + +REDISTRIBUTE_PROTOCOLS = [ + "ospf", + "ospfv3", + "eigrp", + "isis", + "static", + "connected", + "lisp", + "mobile", + "rip", + "subscriber", +] + + +@register_provider("iosxr", "iosxr_bgp") +class Provider(CliProvider): + def render(self, config=None): + commands = list() + + existing_as = None + if config: + match = re.search(r"router bgp (\d+)", config, re.M) + if match: + existing_as = match.group(1) + + operation = self.params["operation"] + + context = None + + if self.params["config"]: + context = "router bgp %s" % self.get_value("config.bgp_as") + + if operation == "delete": + if existing_as: + commands.append("no router bgp %s" % existing_as) + elif context: + commands.append("no %s" % context) + + else: + if operation == "replace": + if existing_as and int(existing_as) != self.get_value( + "config.bgp_as", + ): + # The negate command has to be committed before new BGP AS is used. + self.connection.edit_config( + "no router bgp %s" % existing_as, + ) + config = None + + elif operation == "override": + if existing_as: + # The negate command has to be committed before new BGP AS is used. + self.connection.edit_config( + "no router bgp %s" % existing_as, + ) + config = None + + context_commands = list() + + for key, value in iteritems(self.get_value("config")): + if value is not None: + meth = getattr(self, "_render_%s" % key, None) + if meth: + resp = meth(config) + if resp: + context_commands.extend(to_list(resp)) + + if context and context_commands: + commands.append(context) + commands.extend(context_commands) + commands.append("exit") + + return commands + + def _render_router_id(self, config=None): + cmd = "bgp router-id %s" % self.get_value("config.router_id") + if not config or cmd not in config: + return cmd + + def _render_log_neighbor_changes(self, config=None): + cmd = "bgp log neighbor changes" + log_neighbor_changes = self.get_value("config.log_neighbor_changes") + if log_neighbor_changes is True: + if not config or cmd not in config: + return "%s detail" % cmd + elif log_neighbor_changes is False: + if config and cmd in config: + return "%s disable" % cmd + + def _render_neighbors(self, config): + """generate bgp neighbor configuration""" + return Neighbors(self.params).render(config) + + def _render_address_family(self, config): + """generate address-family configuration""" + return AddressFamily(self.params).render(config) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/module.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/module.py new file mode 100644 index 00000000..afb9b9e7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/module.py @@ -0,0 +1,71 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import Connection + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers import providers + + +class NetworkModule(AnsibleModule): + + fail_on_missing_provider = True + + def __init__(self, connection=None, *args, **kwargs): + super(NetworkModule, self).__init__(*args, **kwargs) + + if connection is None: + connection = Connection(self._socket_path) + + self.connection = connection + + @property + def provider(self): + if not hasattr(self, "_provider"): + capabilities = self.from_json(self.connection.get_capabilities()) + + network_os = capabilities["device_info"]["network_os"] + network_api = capabilities["network_api"] + + if network_api == "cliconf": + connection_type = "network_cli" + + cls = providers.get( + network_os, + self._name.split(".")[-1], + connection_type, + ) + + if not cls: + msg = "unable to find suitable provider for network os %s" % network_os + if self.fail_on_missing_provider: + self.fail_json(msg=msg) + else: + self.warn(msg) + + obj = cls(self.params, self.connection, self.check_mode) + + setattr(self, "_provider", obj) + + return getattr(self, "_provider") + + def get_facts(self, subset=None): + try: + self.provider.get_facts(subset) + except Exception as exc: + self.fail_json(msg=to_text(exc)) + + def edit_config(self, config_filter=None): + current_config = self.connection.get_config(flags=config_filter) + try: + commands = self.provider.edit_config(current_config) + changed = bool(commands) + return {"commands": commands, "changed": changed} + except Exception as exc: + self.fail_json(msg=to_text(exc)) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/providers.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/providers.py new file mode 100644 index 00000000..94220ffa --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/providers/providers.py @@ -0,0 +1,127 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import json + +from threading import RLock + +from ansible.module_utils.six import itervalues +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list + + +_registered_providers = {} +_provider_lock = RLock() + + +def register_provider(network_os, module_name): + def wrapper(cls): + _provider_lock.acquire() + try: + if network_os not in _registered_providers: + _registered_providers[network_os] = {} + for ct in cls.supported_connections: + if ct not in _registered_providers[network_os]: + _registered_providers[network_os][ct] = {} + for item in to_list(module_name): + for entry in itervalues(_registered_providers[network_os]): + entry[item] = cls + finally: + _provider_lock.release() + return cls + + return wrapper + + +def get(network_os, module_name, connection_type): + network_os_providers = _registered_providers.get(network_os) + if network_os_providers is None: + raise ValueError("unable to find a suitable provider for this module") + if connection_type not in network_os_providers: + raise ValueError("provider does not support this connection type") + elif module_name not in network_os_providers[connection_type]: + raise ValueError("could not find a suitable provider for this module") + return network_os_providers[connection_type][module_name] + + +class ProviderBase(object): + + supported_connections = () + + def __init__(self, params, connection=None, check_mode=False): + self.params = params + self.connection = connection + self.check_mode = check_mode + + @property + def capabilities(self): + if not hasattr(self, "_capabilities"): + resp = self.from_json(self.connection.get_capabilities()) + setattr(self, "_capabilities", resp) + return getattr(self, "_capabilities") + + def get_value(self, path): + params = self.params.copy() + for key in path.split("."): + params = params[key] + return params + + def get_facts(self, subset=None): + raise NotImplementedError(self.__class__.__name__) + + def edit_config(self): + raise NotImplementedError(self.__class__.__name__) + + +class CliProvider(ProviderBase): + + supported_connections = ("network_cli",) + + @property + def capabilities(self): + if not hasattr(self, "_capabilities"): + resp = self.from_json(self.connection.get_capabilities()) + setattr(self, "_capabilities", resp) + return getattr(self, "_capabilities") + + def get_config_context(self, config, path, indent=1): + if config is not None: + netcfg = NetworkConfig(indent=indent, contents=config) + try: + config = netcfg.get_block_config(to_list(path)) + except ValueError: + config = None + return config + + def render(self, config=None): + raise NotImplementedError(self.__class__.__name__) + + def cli(self, command): + try: + if not hasattr(self, "_command_output"): + setattr(self, "_command_output", {}) + return self._command_output[command] + except KeyError: + out = self.connection.get(command) + try: + out = json.loads(out) + except ValueError: + pass + self._command_output[command] = out + return out + + def get_facts(self, subset=None): + return self.populate() + + def edit_config(self, config=None): + commands = self.render(config) + if commands and self.check_mode is False: + self.connection.edit_config(commands) + return commands diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/acl_interfaces.py new file mode 100644 index 00000000..c2cf4f90 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/acl_interfaces.py @@ -0,0 +1,64 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Acl_interfacesTemplate(NetworkTemplate): + def __init__(self, lines=None): + super(Acl_interfacesTemplate, self).__init__(lines=lines, tmplt=self) + + # fmt: off + PARSERS = [ + { + 'name': 'interface', + 'getval': re.compile( + r''' + ^interface + \s(preconfigure)*\s* + (?P<name>\S+)$''', re.VERBOSE, + ), + 'setval': 'interface {{ name }}', + 'result': { + '{{ name }}': { + 'name': '{{ name }}', + 'access_groups': {}, + }, + }, + 'shared': True, + }, + { + "name": "access_groups", + "getval": re.compile( + r""" + \s+(?P<afi>ipv4|ipv6) + \saccess-group\s(?P<acl_name>\S+) + \s(?P<direction>\S+)$ + """, + re.VERBOSE, + ), + "setval": "{{ afi }} access-group {{ name }} {{ 'egress' if direction == 'out' else 'ingress' }}", + "result": { + "{{ name }}": { + "access_groups": { + "{{ afi }}": { + "afi": "{{ afi }}", + "acls": [ + { + "name": "{{ acl_name }}", + "direction": "{{ 'in' if direction == 'ingress' else 'out' }}", + }, + ], + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_address_family.py new file mode 100644 index 00000000..a1d9bfda --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_address_family.py @@ -0,0 +1,1182 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Bgp_address_family parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def _tmplt_aggregate_address(aggaddr): + cmd = "aggregate-address {value}" + + if aggaddr.get("as_set"): + cmd += " as-set" + if aggaddr.get("as_confed_set"): + cmd += " as-confed-set" + if aggaddr.get("summary_only"): + cmd += " summary-only" + if aggaddr.get("route_policy"): + cmd += " route-policy {route_policy}" + + return cmd.format(**aggaddr) + + +def _tmpl_allocate_label(config_data): + if "allocate_label" in config_data: + command = "allocate-label" + if "all" in config_data["allocate_label"]: + command += " all" + + if "route_policy" in config_data["allocate_label"]: + command += " route-policy {route_policy}".format(**config_data["route_policy"]) + + return command + + +def _tmpl_bgp_origin_as_validation(config_data): + origin_as_conf = config_data.get("bgp", {}).get("origin_as", {}).get("validation") + if origin_as_conf: + command = [] + if "disable" in origin_as_conf: + command.append("bgp origin-as validation disable") + if "ibgp" in origin_as_conf.get("signal", {}): + command.append("bgp origin-as validation signal ibgp") + + return command + + +def _tmpl_bgp_dampening(config_data): + dampening_conf = config_data.get("bgp", {}).get("dampening", {}) + if dampening_conf: + command = "bgp dampening" + if "value" in dampening_conf: + command += " " + str(dampening_conf["value"]) + if "route_policy" in dampening_conf: + command += " route-policy " + dampening_conf["route_policy"] + + return command + + +def _tmpl_maximum_paths_ibgp(config_data): + + ibgp_conf = config_data.get("maximum_paths", {}).get("ibgp", {}) + if ibgp_conf: + command = "maximum-paths ibgp" + if "max_path_value" in ibgp_conf: + command += " " + str(ibgp_conf["max_path_value"]) + if "order_igp_metric" in ibgp_conf: + command += " order igp-metric" + elif "selective_order_igp_metric" in ibgp_conf: + command += " selective order igp-metric" + elif "set" in ibgp_conf.get("unequal_cost", {}): + command += " unequal-cost" + if "order_igp_metric" in ibgp_conf.get("unequal_cost", {}): + command += " order igp-metric" + elif "selective_order_igp_metric" in ibgp_conf.get( + "unequal_cost", + {}, + ): + command += " selective order igp-metric" + return command + + +def _tmpl_maximum_paths_ebgp(config_data): + + ebgp_conf = config_data.get("maximum_paths", {}).get("ebgp", {}) + if ebgp_conf: + command = "maximum-paths ebgp" + if "max_path_value" in ebgp_conf: + command += " " + str(ebgp_conf["max_path_value"]) + if "order_igp_metric" in ebgp_conf: + command += " order igp-metric" + elif "selective_order_igp_metric" in ebgp_conf: + command += " selective order igp-metric" + return command + + +def _tmpl_maximum_paths_eibgp(config_data): + + eibgp_conf = config_data.get("maximum_paths", {}).get("eibgp", {}) + if eibgp_conf: + command = "maximum-paths ebgp" + if "max_path_value" in eibgp_conf: + command += " " + str(eibgp_conf["max_path_value"]) + if "order_igp_metric" in eibgp_conf: + command += " order igp-metric" + elif "selective_order_igp_metric" in eibgp_conf: + command += " selective order igp-metric" + return command + + +def _tmpl_network(config_data): + cmd = "network {network}" + if config_data.get("backdoor_route_policy"): + cmd += " backdoor-route-policy {backdoor-route-policy}" + if config_data.get("route_policy"): + cmd += " route-policy {route_policy}" + return cmd.format(**config_data) + + +def _tmpl_nexthop(config_data): + nexthop_conf = config_data.get("nexthop", {}) + commands = [] + if nexthop_conf: + + if "resolution_prefix_length_minimum" in nexthop_conf: + command = "nexthop resolution prefix-length minimum " + str( + nexthop_conf["resolution_prefix_length_minimum"], + ) + commands.append(command) + if "trigger_delay_critical" in nexthop_conf: + command = "nexthop trigger-delay critical " + str( + nexthop_conf["trigger_delay_non_critical"], + ) + commands.append(command) + if "trigger_delay_non_critical" in nexthop_conf: + command = "nexthop trigger-delay non-critical " + str( + nexthop_conf["trigger_delay_non_critical"], + ) + commands.append(command) + if "route_policy" in nexthop_conf: + command += " route-policy " + nexthop_conf["route_policy"] + + return commands + + +def _tmpl_optimal_route(config_data): + orr_conf = config_data.get("optimal_route_reflection", {}) + if orr_conf: + command = "optimal-route-reflection" + if "group_name" in orr_conf: + command += " " + str(orr_conf["value"]) + if "primary_address" in orr_conf: + command += " " + orr_conf["primary_address"] + if "secondary_address" in orr_conf: + command += " " + orr_conf["secondary_address"] + return command + + +def _tmpl_update(config_data): + update_conf = config_data.get("update", {}) + update_wait = config_data.get("update", {}).get("wait_install") + update_limit = config_data.get("update", {}).get("limit", {}) + commands = [] + if update_conf: + if update_wait: + command = "update wait-install" + commands.append(command) + if "address_family" in update_limit: + command = "update limit address-family " + str( + update_limit["address_family"], + ) + commands.append(command) + if "sub_group" in update_limit: + if "ibgp" in update_limit["sub_group"]: + command = "update limit sub-group ibgp " + str( + update_limit["sub_group"]["ibgp"], + ) + commands.append(command) + if "ebgp" in update_limit["sub_group"]: + command = "update limit sub-group ebgp " + str( + update_limit["sub_group"]["ebgp"], + ) + commands.append(command) + return commands + + +def _tmplt_redistribute(redis): + command = "redistribute {protocol}".format(**redis) + if redis.get("id"): + command += " {id}".format(**redis) + if redis.get("metric"): + command += " metric {metric}".format(**redis) + if redis.get("level"): + command += " level {level}".format(**redis) + if redis.get("internal"): + command += " internal" + if redis.get("external"): + command += " external" + if redis.get("nssa_external"): + command += " nssa-external" + if redis.get("external_ospf"): + command += " external {external_ospf}".format(**redis) + if redis.get("route_policy"): + command += " route-policy {route_policy}".format(**redis) + return command + + +def _tmpl_vrf_all(config_data): + conf = config_data.get("vrf_all", {}) + commands = [] + if conf: + if "source_rt_import_policy" in conf: + commands.append("vrf all source rt import-policy") + if "label_mode" in conf: + command = "vrf all label mode" + if "per_ce" in conf.get("label_mode"): + command += " per-ce" + elif "per_vrf" in conf.get("label_mode"): + command += " per-vrf" + elif "route_policy" in conf.get("label_mode"): + command += " route-policy " + conf["route_policy"] + if "table_policy" in conf: + command = "vrf all table-policy " + conf["table_policy"] + commands.append(command) + return command + + +def _tmpl_wt(config_data): + conf = config_data.get("weight", "") + if conf: + command = "weight" + if "reset_on_import" in conf: + command += " reset-on-import" + elif "reset_on_import_disable" in conf: + command += " reset-on-import disable" + return command + + +def _tmpl_label_mode(conf): + if "label_mode" in conf: + command = "vrf all label mode" + if "per_ce" in conf.get("label_mode"): + command += " per-ce" + elif "per_vrf" in conf.get("label_mode"): + command += " per-vrf" + elif "per_prefix" in conf.get("label_mode"): + command += " per-prefix" + elif "route_policy" in conf.get("label_mode"): + command += " route-policy " + conf["route_policy"] + return command + + +class Bgp_address_familyTemplate(NetworkTemplate): + def __init__(self, lines=None): + super(Bgp_address_familyTemplate, self).__init__( + lines=lines, + tmplt=self, + ) + + # fmt: off + PARSERS = [ + { + "name": "router", + "getval": re.compile( + r""" + ^router\s + bgp + \s(?P<as_num>\S+) + $""", + re.VERBOSE, + ), + "setval": "router bgp {{ as_number }}", + "result": {"as_number": "{{ as_num }}"}, + "shared": True, + }, + { + "name": "vrf", + "getval": re.compile( + r""" + \s+vrf + \s(?P<vrf>\b(?!all\b)\S+)$""", + re.VERBOSE, + ), + "setval": "vrf {{ vrf }}", + "result": { + }, + "shared": True, + }, + { + "name": "address_family", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\b(?!all\b)\S+))? + (?P<address_family>\s+address-family\s(?P<afi>\S+)\s(?P<safi>\S+)) + $""", re.VERBOSE, + ), + "setval": "address-family {{ afi}} {{safi}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "afi": "{{ afi}}", + "safi": "{{safi}}", + "vrf": "{{ vrf }}", + }, + }, + }, + "shared": True, + }, + { + "name": "advertise_best_external", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+advertise\s(?P<abe>best-external) + $""", re.VERBOSE, + ), + "setval": "advertise best-external", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "advertise_best_external": "{{True if abe is defined}}", + }, + }, + }, + }, + { + "name": "allocate_label", + "getval": re.compile( + r""" + \s+allocate-label\s(?P<all>all) + (\sroute-policy\s(?P<route_policy>\S+))? + $""", re.VERBOSE, + ), + "setval": _tmpl_allocate_label, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "allocate_label": { + "all": "{{True if all is defined}}", + "route_policy": "{{route_policy}}", + }, + }, + }, + }, + }, + + { + "name": "aggregate_address", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+aggregate-address\s(?P<value>\S+) + (\sas-set(?P<as_set>))? + (\sas-confed-set(?P<as_confed_set>))? + (\ssummary-only(?P<summery_only>))? + (\sroute-policy\s(?P<route_policy>\S+))? + $""", re.VERBOSE, + ), + "setval": _tmplt_aggregate_address, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "aggregate_address": [ + { + "as_set": "{{True if as_set is defined}}", + "as_confed_set": "{{True if as_confed_set is defined}}", + "summary_only": "{{True if summery_only is defined}}", + "value": "{{value}}", + "route_policy": "{{route_policy}}", + }, + ], + }, + }, + }, + + }, + { + "name": "additional_paths", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+additional-paths\s(?P<value>\S+) + $""", re.VERBOSE, + ), + "setval": "additional-paths {{additional_paths}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "additional_paths": "{{value}}", + }, + }, + }, + }, + { + "name": "as_path_loopcheck_out_disable", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+as-path-loopcheck\sout(?P<value>\sdisable) + $""", re.VERBOSE, + ), + "setval": "as-path-loopcheck out disable", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "as_path_loopcheck_out_disable": "{{True if value is defined }}", + }, + }, + }, + }, + { + "name": "bgp_attribute_download", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+bgp\s(?P<value>attribute-download) + $""", re.VERBOSE, + ), + "setval": "bgp attribute-download", + "compval": "bgp.attribute_download", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d()}}': { + "bgp": { + "attribute_download": "{{True if value is defined }}", + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_origin_as_use", + "getval": re.compile( + r""" + \s+bgp\sbestpath\s(?P<origin_as>origin-as\suse\svalidity) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath origin-as use validity", + "compval": "bgp.bestpath.origin_as.use", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": {"origin_as": {"use": {"validity": "{{True if origin_as is defined }}"}}}, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_origin_as_allow", + "getval": re.compile( + r""" + \s+bgp\sbestpath\s(?P<origin_as>origin-as\sallow\sinvalid) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath origin-as allow invalid", + "compval": "bgp.bestpath.origin_as.allow", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "origin_as": {"allow": {"invalid": "{{True if origin_as is defined }}"}}, + }, + }, + }, + }, + }, + + }, + { + "name": "bgp_reflection_disable", + "getval": re.compile( + r""" + \s+bgp\sclient-to-client + \sreflection + \sdisable(?P<disable>) + $""", re.VERBOSE, + ), + "setval": "bgp client-to-client reflection disable", + "compval": "bgp.client_to_client.reflection.disable", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "client_to_client": { + "reflection": { + "disable": "{{True if disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_client_to_client_reflection_cluster_id", + "getval": re.compile( + r""" + \s+bgp\sclient-to-client + (\sreflection\scluster-id(?P<cs_id>\s\d+))? + (\sdisable(?P<disable>))? + $""", re.VERBOSE, + ), + "setval": "bgp client-to-clinet reflection cluster-id " + "{{ bgp.client_to_client.reflection.cluster_id }} disable", + "compval": "bgp.client_to_client.reflection.cluster_id", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "client_to_client": { + "reflection": { + "cluster_id_disable": { + "cluster_id": "{{cs_id}}", + "disable": "{{True if disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_dampening", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+bgp\sdampening(?P<set>) + (\s(?P<value>\d+))? + (\sroute-policy\s(?P<route_policy>)\S+)? + $""", re.VERBOSE, + ), + "setval": _tmpl_bgp_dampening, + "compval": "bgp.dampening", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "dampening": { + "set": "{{True if set is defined}}", + "value": "{{value}}", + "route_policy": "{{route_policy}}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_label_delay", + "getval": re.compile( + r""" + \s+bgp\slabel-delay(?P<set>) + (\s(?P<first>\S+)) + (\s(?P<second>\S+)) + $""", re.VERBOSE, + ), + "setval": "bgp label-delay {{ bgp.label_delay.delay_second_parts}} {{ bgp.label_delay.delay_ms_parts}}", + "compval": "bgp.label_delay", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "label_delay": { + "delay_second_parts": "{{first}}", + "delay_ms_parts": "{{second}}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_import_delay", + "getval": re.compile( + r""" + \s+bgp\simport-delay(?P<set>) + (\s(?P<first>\S+)) + (\s(?P<second>\S+)) + $""", re.VERBOSE, + ), + "setval": "bgp import-delay {{ bgp.import_delay.delay_second_parts}} {{ bgp.import_delay.delay_ms_parts}}", + "compval": "bgp.import_delay", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "import_delay": { + "delay_second_parts": "{{first}}", + "delay_ms_parts": "{{second}}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_origin_as_validation", + "getval": re.compile( + r""" + \s+bgp\sorigin-as\svalidation + (\s(?P<disable>disable))? + (\ssignal\s(?P<signal>ibgp))? + $""", re.VERBOSE, + ), + "setval": _tmpl_bgp_origin_as_validation, + "compval": "bgp.origin_as.validation", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "origin_as": { + "validation": { + "disable": "{{True if disable is defined}}", + "signal": { + "ibgp": "{{True if signal is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_scan_time", + "getval": re.compile( + r""" + \s+bgp\sscan-time\s(?P<scan_time>\d+) + $""", re.VERBOSE, + ), + "setval": "bgp scan-time {{bgp.scan_time}}", + "compval": "bgp.scan_time", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "bgp": { + "scan_time": "{{scan_time}}", + }, + }, + }, + }, + }, + { + "name": "default_martian_check_disable", + "getval": re.compile( + r""" + \s+default-martian-check(?P<disable>\sdisable) + $""", re.VERBOSE, + ), + "setval": "default-martian-check disable", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "default_martian_check_disable": "{{ True if disable is defined}}", + }, + }, + }, + }, + { + "name": "distance", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+distance\sbgp + (\s(?P<external>\d+))? + (\s(?P<internal>\d+))? + (\s(?P<local>\d+))? + $""", re.VERBOSE, + ), + "setval": "distnace bgp {{distnace.bgp.routes_external_to_as}} " + "{{distnace.bgp.routes_internal_to_as}} {{distnace.bgp.local_routes}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "distance": { + "routes_external_to_as": "{{external}}", + "routes_internal_to_as": "{{internal}}", + "local_routes": "{{local}}", + }, + }, + }, + }, + }, + { + "name": "dynamic_med", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+dynamic-med\sinterval\s(?P<dynamic_med>\d+) + $""", re.VERBOSE, + ), + "setval": "dynamic-med interval {{dynamic_med}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "dynamic_med": "{{ dynamic_med}}", + }, + }, + }, + }, + { + "name": "maximum_paths_ibgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+maximum-paths\sibgp\s((?P<max_path_value>\S+))? + (\sorder\sigp-metric(?P<order_igp_metric>))? + (\sselective\sorder\sigp-metric(?P<selective_order_igp_metric>))? + (\sunequal-cost(?P<unequal_cost>))? + (\sorder\sigp-metric(?P<order_igp_metric1>))? + (\sselective\sorder\sigp-metric(?P<selective_order_igp_metric1>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_maximum_paths_ibgp, + "compval": "maximum_paths.ibgp", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "maximum_paths": { + "ibgp": { + "max_path_value": "{{ max_path_value }}", + "order_igp_metric": "{{ True if order_igp_metric is defined}}", + "selective_order_igp_metric": + "{{ True if selective_order_igp_metric is defined}}", + "unequal_cost": { + "set": "{{ True if unequal_cost is defined}}", + "order_igp_metric": "{{ True if order_igp_metric1 is defined}}", + "selective_order_igp_metric": "{{ True if selective_order_igp_metric1 is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "maximum_paths_ebgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+maximum-paths\sebgp\s((?P<max_path_value>\S+))? + (\sorder\sigp-metric(?P<order_igp_metric>))? + (\sselective\sorder\sigp-metric(?P<selective_order_igp_metric>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_maximum_paths_ebgp, + "compval": "maximum_paths.ebgp", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "maximum_paths": { + "ebgp": { + "max_path_value": "{{ max_path_value }}", + "order_igp_metric": "{{ True if order_igp_metric is defined}}", + "selective_order_igp_metric": + "{{ True if selective_order_igp_metric is defined}}", + + }, + }, + }, + }, + }, + }, + { + "name": "maximum_paths_eibgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+maximum-paths\seibgp\s((?P<max_path_value>\S+))? + (\sorder\sigp-metric(?P<order_igp_metric>))? + (\sselective\sorder\sigp-metric(?P<selective_order_igp_metric>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_maximum_paths_eibgp, + "compval": "maximum_paths.eibgp", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "maximum_paths": { + "eibgp": { + "max_path_value": "{{ max_path_value }}", + "order_igp_metric": "{{ True if order_igp_metric is defined}}", + "selective_order_igp_metric": + "{{ True if selective_order_igp_metric is defined}}", + + }, + }, + }, + }, + }, + }, + { + "name": "networks", + "getval": re.compile( + r""" + \s+network\s(?P<value>\S+) + (\sbackdoor-route-policy\s(?P<backdoor_route_policy>)\S+)? + (\sroute-policy\s(?P<route_policy>)\S+)? + $""", re.VERBOSE, + ), + "setval": _tmpl_network, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "networks": [ + { + "backdoor_route_policy": "{{backdoor_route_policy}}", + "network": "{{value}}", + "route_policy": "{{route_policy}}", + }, + ], + }, + }, + }, + }, + { + "name": "nexthop", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+nexthop + (\sresolution\sprefix-length\sminimum\s(?P<value>\d+))? + (\strigger-delay\scritical\s(?P<trigger_delay_critical>\d+))? + (\strigger-delay\snon-critical\s(?P<trigger_delay_non_critical>\d+))? + (\sroute-policy\s(?P<route_policy>)\S+)? + $""", re.VERBOSE, + ), + "setval": _tmpl_nexthop, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "nexthop": { + "trigger_delay_critical": "{{trigger_delay_critical}}", + "trigger_delay_non_critical": "{{trigger_delay_non_critical}}", + "resolution_prefix_length_minimum": "{{value}}", + "route_policy": "{{route_policy}}", + }, + }, + }, + }, + }, + { + "name": "optimal_route_reflection", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+optimal-route-reflection + (\s(?P<value>\S+))? + (\s(?P<primary>\S+))? + (\s(?P<secondary>\S+))? + $""", re.VERBOSE, + ), + "setval": _tmpl_optimal_route, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "optimal_route_reflection": { + "group_name": "{{value}}", + "primary_address": "{{primary}}", + "secondary_address": "{{secondary}}", + }, + }, + }, + }, + }, + { + "name": "permanent_network_route_policy", + "getval": re.compile( + r""" + \s+permanent-network\s(?P<value>route_policy\S+)? + $""", re.VERBOSE, + ), + "setval": "permanent-network route-policy {{permanent_network_route_policy}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "permanent_network_route_policy": "{{route_policy}}", + }, + }, + }, + }, + { + "name": "retain_local_label", + "getval": re.compile( + r""" + \s+retain\slocal-label\s(?P<value>\d+)? + $""", re.VERBOSE, + ), + "setval": "retain local-label {{retain_local_label}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "retain_local_label": "{{value}}", + }, + }, + }, + }, + { + "name": "update", + "getval": re.compile( + r""" + \s+update + (\slimit)? + (\ssub-group)? + (\sibgp\s(?P<ibgp>\d+))? + (\sebgp\s(?P<ebgp>\d+))? + (\saddress-family\s(?P<af>\d+))? + (\swait-install(?P<wait>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_update, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "update": { + "wait_install": "{{True if wait is defined}}", + "limit": { + "sub_group": { + "ibgp": "{{ibgp}}", + "ebgp": "{{ebgp}}", + }, + "address_family": "{{af}}", + }, + }, + }, + }, + }, + }, + { + "name": "redistribute", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+redistribute + \s(?P<protocol>\S+) + (\s(?P<id>\S+))? + (\smetric\s(?P<metric>\d+))? + (\slevel\s(?P<level>\S+))? + (\sinternal(?P<internal>))? + (\sexternal(?P<external>)(\s(?P<ospf_external>\S+))?)? + (\snssa-external(?P<nssa_external>))? + (\sroute-policy\s(?P<route_policy>\S+))? + $""", re.VERBOSE, + ), + "setval": _tmplt_redistribute, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "redistribute": [ + { + "protocol": "{{protocol}}", + "id": "{{id}}", + "route_policy": "{{route_policy}}", + "metric": "{{metric}}", + "internal": "{{True if internal is defined}}", + "external": "{{True if external is defined}}", + "level": "{{level}}", + "ospf_external": "{{ospf_external}}", + "nssa_external": "{{True if nssa_external is defined}}", + }, + ], + }, + }, + }, + }, + { + "name": "inter_as_install", + "getval": re.compile( + r""" + \s+inter-as\s(?P<inter_as>install) + $""", re.VERBOSE, + ), + "setval": "inter-as install", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "inter_as_install": "{{True if inter_as is defined}}", + }, + }, + }, + + }, + { + "name": "segmented_multicast", + "getval": re.compile( + r""" + \s+(?P<segmented_multicast>segmented-multicast) + $""", re.VERBOSE, + ), + "setval": "segmented-multicast", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "segmented_multicast": "{{True if segmented_multicast is defined}}", + }, + }, + }, + + }, + { + "name": "global_table_multicast", + "getval": re.compile( + r""" + \s+(?P<global_table_multicast>global-table-multicast) + $""", re.VERBOSE, + ), + "setval": "global-table-multicast", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "global_table_multicast": "{{True if global_table_multicast is defined}}", + }, + }, + }, + + }, + { + "name": "table_policy", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + (\s+table-policy\s(?P<table_policy>\S+))? + $""", re.VERBOSE, + ), + "setval": "table-policy {{table_policy}}", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "table_policy": "{{table_policy}}", + }, + }, + }, + }, + { + "name": "vrf_all_conf", + "getval": re.compile( + r""" + \s+vrf\sall + (\s+source\srt(?P<source_rt_import_policy>\simport-policy))? + (\s+table-policy\s(?P<table_policy>\S+))? + (\s+label\smode)? + (\s+(?P<per_ce>per-ce))? + (\s+(?P<per_vrf>per-vrf))? + (\s+route_policy\s(?P<route_policy>\S+))? + $""", re.VERBOSE, + ), + "setval": _tmpl_vrf_all, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "vrf_all_conf": { + "source_rt_import_policy": "{{ True if source_rt_import_policy is defined}}", + "table_policy": "{{table_policy}}", + "label_mode": { + "per_ce": "{{ True if per_ce is defined}}", + "per_vrf": "{{True if per_vrf is defined}}", + "route_policy": "{{route_policy}}", + }, + }, + }, + }, + }, + }, + { + "name": "weight", + "getval": re.compile( + r""" + \s+weight + (\sreset-on-import\sdisable(?P<reset_on_import_disable>))? + (\sreset-on-import(?P<reset_on_import>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_wt, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "weight": { + "reset_on_import_disable": "{{ True if reset_on_import_disable is defined}}", + "reset_on_import": "{{ True if reset_on_import is defined}}", + }, + }, + }, + }, + }, + { + "name": "route_target_download", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+route-target\s(?P<value>download) + $""", re.VERBOSE, + ), + "setval": "route-target download", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "route_target_download": "{{True if value is defined }}", + + }, + }, + }, + }, + { + "name": "mvpn_single_forwarder_selection_all", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+mvpn\ssingle-forwarder-selection\s(?P<value>all) + $""", re.VERBOSE, + ), + "setval": "mvpn single-forwarder-selection all", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "mvpn_single_forwarder_selection_all": "{{True if value is defined }}", + }, + }, + }, + }, + { + "name": "mvpn_single_forwarder_selection_highest_ip_address", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+mvpn\ssingle-forwarder-selection\s(?P<value>highest-ip-address) + $""", re.VERBOSE, + ), + "setval": "mvpn single-forwarder-selection highest-ip-address", + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "mvpn_single_forwarder_selection_highest_ip_address": "{{True if value is defined }}", + }, + }, + }, + }, + { + "name": "label_mode", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+label\smode\s(?P<per_ce>per-ce)?(?P<per_prefix>per-prefix)? + (?P<per_vrf>per-vrf)? + (?P<rr>route-policy\s\S+)? + $""", re.VERBOSE, + ), + "setval": _tmpl_label_mode, + "result": { + "address_family": { + '{{"address_family_" + afi + "_" + safi + "_vrf_" + vrf|d() }}': { + "label_mode": { + "per_ce": "{{ True if per_ce is defined}}", + "per_prefix": "{{ True if per_prefix is defined}}", + "per_vrf": "{{ True if per_vrf is defined}}", + "route_policy": "{{ route_policy}}", + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_global.py new file mode 100644 index 00000000..f584d13f --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_global.py @@ -0,0 +1,3133 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Bgp_global parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def _tmplt_confederation_peers(config_data): + cmds = [] + base_cmd = "bgp confederation peers " + peers = config_data.get("bgp", {}).get("confederation", {}).get("peers") + if peers: + for peer in peers: + cmds.append(base_cmd + str(peer)) + return cmds + + +class Bgp_globalTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Bgp_globalTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "router", + "getval": re.compile( + r""" + ^router\s + bgp + \s(?P<as_num>\S+) + $""", + re.VERBOSE, + ), + "setval": "router bgp {{ as_number }}", + "compval": "as_number", + "result": {"as_number": "{{ as_num }}"}, + "shared": True, + }, + { + "name": "vrf", + "getval": re.compile( + r""" + \s+vrf + \s(?P<vrf>\S+)$""", + re.VERBOSE, + ), + "setval": "vrf {{ vrf }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "vrf": "{{ vrf }}", + }, + }, + }, + "shared": True, + }, + + { + "name": "bfd_minimum_interval", + "getval": re.compile( + r""" + \s+bfd\s(?P<min_interval>minimum-interval\s\d+) + $""", re.VERBOSE, + ), + "compval": "bfd.minimum_interval", + "setval": "bfd minimum-interval {{bfd.minimum_interval}}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bfd": {"minimum_interval": "{{ min_interval.split(" ")[1] }}"}, + }, + }, + }, + }, + { + "name": "bfd_multiplier", + "getval": re.compile( + r""" + \s+bfd\s(?P<multiplier>multiplier\s\d+) + $""", re.VERBOSE, + ), + "setval": "bfd multiplier {{bfd.multiplier}}", + "compval": "bfd.multiplier", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bfd": {"multiplier": "{{multiplier.split(" ")[1]}}"}, + }, + }, + }, + }, + { + "name": "bgp_as_path_loopcheck", + "getval": re.compile( + r""" + \s+bgp\s(?P<loopcheck>as-path-loopcheck) + $""", re.VERBOSE, + ), + "setval": "bgp as-path-loopcheck", + "compval": "bgp.as_path_loopcheck", + "result": { + "bgp": { + "as_path_loopcheck": "{{ True if loopcheck is defined }}", + }, + }, + }, + { + "name": "bgp_auto_policy_soft_reset", + "getval": re.compile( + r""" + \s+bgp\s(?P<auto_policy_soft_reset_disable>auto-policy-soft-reset\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp auto-policy-soft-reset disable", + "compval": "bgp.auto_policy_soft_reset", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "auto_policy_soft_reset": { + "disable": "{{True if auto_policy_soft_reset_disable is defined}}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_cluster_id", + "getval": re.compile( + r""" + \s+bgp\s(?P<cluster_id>cluster-id\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp cluster-id {{bgp.cluster_id}}", + "compval": "bgp.cluster_id", + "result": { + "bgp": { + "cluster_id": "{{cluster_id.split(" ")[1]}}", + }, + }, + }, + { + "name": "bgp_default_local_preference", + "getval": re.compile( + r""" + \s+bgp\s(?P<default_local_pref>default\slocal-preference\s\S+) + $""", re.VERBOSE, + ), + "setval": "bgp default local-preference {{bgp.default.local_preference}}", + "compval": "bgp.default.local-preference", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "default": { + "local_preference": "{{default_local_pref.split(" ")[2] }}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_enforce_first_as_disable", + "getval": re.compile( + r""" + \s+bgp\s(?P<enforce_first_as_disable>enforce-first-as\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp enforce-first-as disable", + "compval": "bgp.enforce_first_as.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "enforce_first_as": { + "disable": "{{ True if enforce_first_as_disable is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_fast_external_fallover_disable", + "getval": re.compile( + r""" + \s+bgp\s(?P<fast_external_fallover_disable>fast-external-fallover\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp fast-external-fallover disable", + "compval": "bgp.fast_external_fallover.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "fast_external_fallover": { + "disable": "{{True if fast_external_fallover_disable is defined}}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_install_diversion", + "getval": re.compile( + r""" + \s+bgp\s(?P<install_diversion>install\sdiversion) + $""", re.VERBOSE, + ), + "setval": "bgp install diversion", + "compval": "bgp.install.diversion", + "result": { + "bgp": { + "install": { + "diversion": "{{True if install_diversion is defined}}", + }, + }, + }, + }, + { + "name": "bgp_max_neighbors", + "getval": re.compile( + r""" + \s+bgp\s(?P<max_neighbors>maximum\sneighbor\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp maximum neighbor {{bgp.maximum.neighbor}}", + "compval": "bgp.maximum.neighbor", + "result": { + "bgp": { + "maximum": + { + "neighbor": "{{max_neighbors.split(" ")[2] }}", + }, + }, + }, + }, + { + "name": "bgp_redistribute_internal", + "getval": re.compile( + r""" + \s+bgp\s(?P<redistribute_internal>redistribute-internal) + $""", re.VERBOSE, + ), + "setval": "bgp redistribute-internal", + "compval": "bgp.redistribute_internal", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "redistribute_internal": "{{ True if redistribute_internal is defined }}", + }, + }, + }, + }, + }, + { + "name": "bgp_router_id", + "getval": re.compile( + r""" + \s+bgp\s(?P<router_id>router-id\s\S+) + $""", re.VERBOSE, + ), + "setval": "bgp router-id {{ bgp.router_id }}", + "compval": "bgp.router_id", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "router_id": "{{router_id.split(" ")[1]}}", + }, + }, + }, + }, + }, + { + "name": "bgp_scan_time", + "getval": re.compile( + r""" + \s+bgp\s(?P<scan_time>scan-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp scan-time {{ bgp.scan_time }}", + "compval": "bgp.scan_time", + "result": { + "bgp": { + "scan_time": "{{scan_time.split(" ")[1]}}", + }, + }, + }, + { + "name": "bgp_unsafe_ebgp_policy", + "getval": re.compile( + r""" + \s+bgp\s(?P<unsafe_ebgp_policy>unsafe-ebgp-policy) + $""", re.VERBOSE, + ), + "setval": "bgp unsafe-ebgp-policy", + "compval": "bgp.unsafe_ebgp_policy", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "unsafe_ebgp_policy": "{{ True if unsafe_ebgp_policy is defined }}", + }, + }, + }, + }, + }, + { + "name": "bgp_update_delay", + "getval": re.compile( + r""" + \s+bgp\s(?P<update_delay>update-delay\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp update-delay {{ bgp.update_delay }}", + "compval": "bgp.update_delay", + "result": { + "bgp": { + "update_delay": "{{update_delay.split(" ")[1]}}", + + }, + }, + }, + { + "name": "bgp_bestpath_aigp", + "getval": re.compile( + r""" + \s+bgp\s(?P<bestpath_aigp_ignore>bestpath\saigp\signore) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath aigp ignore", + "compval": "bgp.bestpath.aigp.ignore", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "aigp": { + "ignore": "{{ True if bestpath_aigp_ignore is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_as_path_ignore", + "getval": re.compile( + r""" + \s+bgp\s(?P<as_path_ignore>bestpath\sas-path\signore) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath as-path ignore", + "compval": "bgp.bestpath.as_path.ignore", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "as_path": { + "ignore": "{{ True if as_path_ignore is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_as_path_multipath_relax", + "getval": re.compile( + r""" + \s+bgp\s(?P<as_path_multipath_relax>bestpath\sas-path\smultipath-relax) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath as-path multipath-relax", + "compval": "bgp.bestpath.as_path.multipath_relax", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "as_path": { + "multipath_relax": "{{ True if as_path_multipath_relax is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_med_always", + "getval": re.compile( + r""" + \s+bgp\s(?P<always>bestpath\smed\salways) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath med always", + "compval": "bgp.bestpath.med.always", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "med": { + "always": "{{ True if always is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_med_confed", + "getval": re.compile( + r""" + \s+bgp\s(?P<confed>bestpath\smed\sconfed) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath med confed", + "compval": "bgp.bestpath.med.confed", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "med": { + "confed": "{{ True if confed is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_med_missing_as_worst", + "getval": re.compile( + r""" + \s+bgp\s(?P<missing_as_worst>bestpath\smed\smissing-as-worst) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath med missing-as-worst)", + "compval": "bgp.bestpath.med.missing_as_worst", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "med": { + "missing_as_worst": "{{ True if missing_as_worst is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_compare_routerid", + "getval": re.compile( + r""" + \s+bgp\s(?P<compare_routerid>bestpath\scompare-routerid) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath compare-routerid", + "compval": "bgp.bestpath.compare_routerid", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "compare_routerid": "{{ True if compare_routerid is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_cost_community_ignore", + "getval": re.compile( + r""" + \s+bgp\s(?P<cost_community_ignore>bestpath\scost-community\signore) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath cost-community ignore", + "compval": "bgp.bestpath.cost_community.ignore", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "cost_community": { + "ignore": "{{ True if cost_community_ignore is defined}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_origin_as_use", + "getval": re.compile( + r""" + \s+bgp\s(?P<origin_as_use>bestpath\sorigin-as\suse\svalidity) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath origin-as use validity", + "compval": "bgp.bestpath.origin_as.use.validity", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "origin_as": { + "use": {"validity": "{{ True if origin_as_use is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_bestpath_origin_as_allow", + "getval": re.compile( + r""" + \s+bgp\s(?P<origin_as_allow>bestpath\sorigin-as\sallow\sinvalid) + $""", re.VERBOSE, + ), + "setval": "bgp bestpath origin-as allow invalid", + "compval": "bgp.bestpath.origin_as.allow.invalid", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "bestpath": { + "origin_as": + { + "allow": {"invalid": "{{ True if origin_as_allow is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp_confederation_identifier", + "getval": re.compile( + r""" + \s+bgp\s(?P<confederation_identifier>confederation\sidentifier\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp confederation identifier {{ bgp.confederation.identifier}}", + "compval": "bgp.confederation.identifier", + "result": { + "bgp": { + "confederation": { + "identifier": "{{confederation_identifier.split(" ")[2]}}", + }, + + }, + }, + }, + { + "name": "bgp_confederation_peers", + "getval": re.compile( + r""" + \s+bgp\s(?P<confederation_peers>confederation\speers\s\d+) + $""", re.VERBOSE, + ), + "setval": _tmplt_confederation_peers, + "compval": "bgp.confederation.peers", + "result": { + "bgp": { + "confederation": { + "peers": { + "peer" + "{{confederation_peers.split(" ")[2]}}": "{{confederation_peers.split(" ")[2]}}", + }, + }, + + }, + }, + }, + { + "name": "bgp_graceful_restart_set", + "getval": re.compile( + r""" + \s+bgp\s(?P<graceful_restart_set>graceful-restart) + $""", re.VERBOSE, + ), + "setval": "bgp graceful-restart", + "compval": "bgp.graceful_restart.set", + "result": { + "bgp": { + "graceful_restart": { + "set": "{{ True if graceful_restart_set is defined }}", + }, + + }, + }, + }, + { + "name": "bgp_graceful_restart_graceful_reset", + "getval": re.compile( + r""" + \s+bgp\s(?P<graceful_restart_graceful_reset>graceful-restart\sgraceful-reset) + $""", re.VERBOSE, + ), + "setval": "bgp graceful-restart graceful-reset", + "compval": "bgp.graceful_restart.graceful_reset", + "result": { + "bgp": { + "graceful_restart": { + "graceful_reset": "{{ True if graceful_restart_graceful_reset is defined}}", + }, + + }, + }, + }, + { + "name": "bgp_graceful_restart_restart_time", + "getval": re.compile( + r""" + \s+bgp\s(?P<graceful_restart_restart_time>graceful-restart\srestart-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp graceful-restart restart-time {{ bgp.graceful_restart.restart_time}}", + "compval": "bgp.graceful_restart.restart_time", + "result": { + "bgp": { + "graceful_restart": { + "restart_time": "{{ graceful_restart_restart_time.split(" ")[2] }}", + }, + + }, + }, + }, + { + "name": "bgp_graceful_restart_purge_time", + "getval": re.compile( + r""" + \s+bgp\s(?P<graceful_restart_purge_time>graceful-restart\spurge-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp graceful-restart purge-time {{ bgp.graceful_restart.purge_time}}", + "compval": "bgp.graceful_restart.purge_time", + "result": { + "bgp": { + "graceful_restart": { + "purge_time": "{{ graceful_restart_purge_time.split(" ")[2] }}", + }, + + }, + }, + }, + { + "name": "bgp_graceful_restart_stalepath_time", + "getval": re.compile( + r""" + \s+bgp\s(?P<graceful_restart_stalepath_time>graceful-restart\sstalepath-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp graceful-restart stalepath-time {{ bgp.graceful_restart.stalepath_time}}", + "compval": "bgp.graceful_restart.stalepath_time", + "result": { + "bgp": { + "graceful_restart": { + "stalepath_time": "{{ graceful_restart_stalepath_time.split(" ")[2] }}", + }, + + }, + }, + }, + { + "name": "bgp_log_message", + "getval": re.compile( + r""" + \s+bgp\s(?P<log_message>log\smessage\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp log message disable", + "compval": "bgp.log_message.message.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "log": { + "log_message": {"disable": "{{ True if log_message is defined }}"}, + }, + }, + }, + + }, + }, + }, + { + "name": "bgp_log_neighbor_changes_detail", + "getval": re.compile( + r""" + \s+bgp\s(?P<log_neighbor_changes_detail>log\sneighbor\schanges\sdetail) + $""", re.VERBOSE, + ), + "setval": "bgp log neighbor changes detail", + "compval": "bgp.log.neighbor.changes.detail", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "log": { + "neighbor": { + "changes": { + "detail": "{{True if log_neighbor_changes_detail is defined }}", + }, + }, + }, + }, + }, + + }, + }, + }, + { + "name": "bgp_log_neighbor_changes_disable", + "getval": re.compile( + r""" + \s+bgp\s(?P<log_neighbor_changes_disable>log\sneighbor\schanges\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp log neighbor changes disable", + "compval": "bgp.log.neighbor.changes.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "log": { + "neighbor": { + "changes": { + "disable": + "{{ True if log_neighbor_changes_disable is defined }}", + }, + }, + }, + }, + }, + + }, + }, + }, + { + "name": "bgp_multipath_as_path_ignore_onwards", + "getval": re.compile( + r""" + \s+bgp\s(?P<multipath>multipath\sas-path\signore\sonwards) + $""", re.VERBOSE, + ), + "setval": "bgp multipath as-path ignore onwards", + "compval": "bgp.multipath.as_path.ignore.onwards", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "bgp": { + "multipath": { + "as_path": {"ignore": {"onwards": "{{ not not multipath}}"}}, + }, + }, + }, + + }, + }, + }, + { + "name": "bgp_origin_as_validation_disable", + "getval": re.compile( + r""" + \s+bgp\s(?P<origin_as_validation_disable>origin-as\svalidation\sdisable) + $""", re.VERBOSE, + ), + "setval": "bgp origin-as validation disable", + "compval": "bgp.origin_as.validation.disable", + "result": { + "bgp": { + "origin_as": { + "validation": {"disable": "{{ not not origin_as_validation_disable}}"}, + }, + + }, + }, + }, + { + "name": "bgp_origin_as_validation_signal_ibgp", + "getval": re.compile( + r""" + \s+bgp\s(?P<origin_as_validation_signal_ibgp>origin-as\svalidation\ssignal\sibgp) + $""", re.VERBOSE, + ), + "setval": "bgp origin-as validation signal ibgp", + "compval": "bgp.origin_as.validation.signal.ibgp", + "result": { + "bgp": { + "origin_as": { + "validation": {"signal": {"ibgp": "{{ not not origin_as_validation_signal_ibgp }}"}}, + }, + + }, + }, + }, + { + "name": "bgp_origin_as_validation_time_off", + "getval": re.compile( + r""" + \s+bgp\s(?P<validation_time_off>origin-as\svalidation\stime\soff) + $""", re.VERBOSE, + ), + "setval": "bgp origin-as validation time off", + "compval": "bgp.origin_as.validation.time.off", + "result": { + "bgp": { + "origin_as": { + "validation": {"time": {"time_off": "{{ not not validation_time_off }}"}}, + }, + + }, + }, + }, + { + "name": "bgp_origin_as_validation_time", + "getval": re.compile( + r""" + \s+bgp\s(?P<validation_time>origin-as\svalidation\stime\s\d+) + $""", re.VERBOSE, + ), + "setval": "bgp origin-as validation time {{ bgp.origin_as.validation.time.time_in_second }}", + "compval": "bgp.origin_as.validation.time.time_in_second", + "result": { + "bgp": { + "origin_as": { + "validation": {"time": {"time_in_second": "{{ validation_time.split(" ")[3] }}"}}, + }, + + }, + }, + }, + + { + "name": "bgp_default_information_originate", + "getval": re.compile( + r""" + \s+default-information\s(?P<default_information_originate>originate) + $""", re.VERBOSE, + ), + "setval": "default-information originate", + "compval": "default_information.originate", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "default_information": { + "originate": "{{ not not default_information_originate }}", + }, + }, + }, + }, + }, + { + "name": "bgp_default_metric", + "getval": re.compile( + r""" + \s+default-metric\s(?P<default_metric>\d+) + $""", re.VERBOSE, + ), + "setval": "default-metric {{default_metric}}", + "compval": "default_metric", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "default_metric": "{{ default_metric }}", + }, + }, + }, + }, + { + "name": "bgp_graceful_maintenance", + "getval": re.compile( + r""" + \s+graceful-maintenance\sactivate\s(?P<graceful_maintenance>\S*) + $""", re.VERBOSE, + ), + "setval": "graceful_maintenance {{graceful_maintenance.activate}}", + "compval": "graceful_maintenance.activate", + "result": { + "graceful_maintenance": {"activate": "{{ graceful_maintenance }}"}, + }, + }, + { + "name": "ibgp_policy_out_enforce_modifications", + "getval": re.compile( + r""" + \s+ibgp\spolicy\sout\s(?P<ibgp_policy_out>enforce-modifications) + $""", re.VERBOSE, + ), + "setval": "ibgp policy out enforce-modifications", + "compval": "ibgp.policy.out.enforce_modifications", + "result": { + "ibgp": {"policy": {"out": {"enforce_modifications": "{{ not not ibgp_policy_out }}"}}}, + }, + }, + { + "name": "mpls_activate_interface", + "getval": re.compile( + r""" + \s+mpls\sactivate\sinterface(?P<mpls_interface>\S+) + $""", re.VERBOSE, + ), + "setval": "mpls activate interface {{mpls.activate.interface}}", + "compval": "mpls.activate.interface", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "mpls": {"activate": {"interface": "{{ mpls_interface }}"}}, + }, + }, + }, + }, + { + "name": "mvpn", + "getval": re.compile( + r""" + \s(?P<mvpn>mvpn) + $""", re.VERBOSE, + ), + "setval": "mvpn", + "compval": "mvpn", + "result": { + "mvpn": "{{ not not mvpn }}", + }, + }, + { + "name": "nsr_set", + "getval": re.compile( + r""" + \s(?P<nsr>nsr\s*) + $""", re.VERBOSE, + ), + "setval": "nsr", + "compval": "nsr.set", + "result": { + "nsr": {"set": "{{ not not nsr }}"}, + }, + }, + { + "name": "nsr_disable", + "getval": re.compile( + r""" + \snsr\s(?P<nsr_disable>disable\s*) + $""", re.VERBOSE, + ), + "setval": "nsr disable", + "compval": "nsr.disable", + "result": { + "nsr": {"disable": "{{ not not nsr_disable }}"}, + }, + }, + { + "name": "socket_receive_buffer_size", + "getval": re.compile( + r""" + \s+socket\s(?P<socket_rcv_buffer_size>receive-buffer-size\s\d+) + $""", re.VERBOSE, + ), + "setval": "socket receive-buffer-size {{ socket.receive_buffer_size}}", + "compval": "socket.receive_buffer_size", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "socket": {"receive_buffer_size": "{{ socket_rcv_buffer_size.split(" ")[1] }}"}, + }, + }, + }, + }, + { + "name": "socket_send_buffer_size", + "getval": re.compile( + r""" + \s+socket\s(?P<socket_send_buffer_size>send-buffer-size\s\d+) + $""", re.VERBOSE, + ), + "setval": "socket send-buffer-size {{ socket.send_buffer_size}}", + "compval": "socket.send_buffer_size", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "socket": {"send_buffer_size": "{{ socket_send_buffer_size.split(" ")[1] }}"}, + }, + }, + }, + }, + { + "name": "update_in_error_handling_basic_ebgp_disable", + "getval": re.compile( + r""" + \s+update\sin\serror-handling\sbasic\sebgp\s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "update in error-handling basic ebgp disable", + "compval": "update.in.error_handling.basic.ebgp.disable", + "result": { + "update": {"in": {"error_handling": {"basic": {"ebgp": {"disable": "{{ not not disable }}"}}}}}, + }, + }, + { + "name": "update_in_error_handling_basic_ibgp_disable", + "getval": re.compile( + r""" + \s+update\sin\serror-handling\sbasic\sibgp\s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "update in error-handling basic ibgp disable", + "compval": "update.in.error_handling.basic.ibgp.disable", + "result": { + "update": {"in": {"error_handling": {"basic": {"ibgp": {"disable": "{{ not not disable }}"}}}}}, + }, + }, + { + "name": "update_in_error_handling_extended_ebgp", + "getval": re.compile( + r""" + \s+update\sin\serror-handling\sextended\s(?P<extended_ebgp>ebgp) + $""", re.VERBOSE, + ), + "setval": "update in error-handling extended ebgp", + "compval": "update.in.error_handling.extended.ebgp", + "result": { + "update": {"in": {"error_handling": {"extended": {"ebgp": "{{ not not extended_ebgp}}"}}}}, + }, + }, + { + "name": "update_in_error_handling_extended_ibgp", + "getval": re.compile( + r""" + \s+update\sin\serror-handling\sextended\s(?P<extended_ibgp>ibgp) + $""", re.VERBOSE, + ), + "setval": "update in error-handling extended ibgp", + "compval": "update.in.error_handling.extended.ibgp", + "result": { + "update": {"in": {"error_handling": {"extended": {"ibgp": "{{ not not extended_ibgp}}"}}}}, + }, + }, + { + "name": "update_out_logging", + "getval": re.compile( + r""" + \s+update\sout\s(?P<update_out_logging>logging) + $""", re.VERBOSE, + ), + "setval": "update out logging", + "compval": "update.out.logging", + "result": { + "update": {"out": {"logging": "{{ not not update_out_logging}}"}}, + }, + }, + { + "name": "update_limit", + "getval": re.compile( + r""" + \s+update\slimit\s(?P<update_limit>\d+) + $""", re.VERBOSE, + ), + "setval": "update limit {{ update.limit }}", + "compval": "update.limit", + "result": { + "update": {"limit": "{{ update_limit}}"}, + }, + }, + { + "name": "rpki_route_value", + "getval": re.compile( + r""" + \srpki + \sroute + \s(?P<value>\S+) + \smax + \s(?P<max>\d+) + \sorigin + \s(?P<origin>\d+) + $""", re.VERBOSE, + ), + "setval": "rpki route {{ rpki.route.value }} max {{rpki.route.max }} " + "origin {{rpki.route.origin }}", + "compval": "rpki.route", + "result": { + "rpki": { + "route": { + "value": "{{value}}", + "origin": "{{origin}}", + "max": "{{max}}", + }, + }, + }, + }, + { + "name": "rpki_server_name", + "getval": re.compile( + r""" + \srpki + \s(?P<value>server\s\S+) + $""", re.VERBOSE, + ), + "setval": "rpki server {{ name }}", + "compval": "rpki.server.name", + "result": { + "rpki": + { + "servers": {"{{value.split(" ")[1]}}": {"name": "{{ value.split(" ")[1] }}"}}, + }, + }, + }, + { + "name": "rpki_server_purge_time", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \s(?P<purge_time>purge-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "purge-time {{ purge_time }}", + "compval": "purge_time", + "result": { + "rpki": + { + "servers": {"{{rpki_server.split(" ")[1]}}": {"purge_time": "{{ purge_time.split(" ")[1] }}"}}, + }, + }, + }, + { + "name": "rpki_server_refresh_time", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \s(?P<refresh_time>refresh-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "refresh-time {{ refresh_time.value }}", + "compval": "refresh_time.value", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1]}}": { + "refresh_time": { + "value": "{{ refresh_time.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "rpki_server_refresh_time_off", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \srefresh-time + \s(?P<refresh_time>off) + $""", re.VERBOSE, + ), + "setval": "refresh-time off", + "compval": "refresh_time.time_off", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1] }}": { + "refresh_time": { + "time_off": "{{ True if refresh_time is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "rpki_server_response_time_off", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \sresponse-time + \s(?P<response_time>off) + $""", re.VERBOSE, + ), + "setval": "response-time off", + "compval": "response_time.time_off", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1]}}": { + "response_time": { + "time_off": "{{ True if response_time is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "rpki_server_response_time", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>\sserver\S+) + \s(?P<response_time>response-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "response-time {{ response_time.value }}", + "compval": "response_time.value", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1]}}": { + "response_time": { + "value": "{{ response_time.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "rpki_server_shutdown", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \s(?P<shutdown>shutdown) + $""", re.VERBOSE, + ), + "setval": "shutdown", + "compval": "shutdown", + "result": { + "rpki": { + "servers": {"{{rpki_server.split(" ")[1]}}": {"shutdown": "{{ True if shutdown is defined}}"}}, + }, + }, + }, + { + "name": "rpki_server_transport_ssh", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \stransport + \sssh + \s(?P<ssh_port>port\s\d+) + $""", re.VERBOSE, + ), + "setval": "transport ssh port {{ transport.ssh.port }}", + "compval": "transport.ssh.port", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1]}}": { + "transport": { + "ssh": { + "port": "{{ ssh_port.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "rpki_server_transport_tcp", + "getval": re.compile( + r""" + \srpki + \s(?P<rpki_server>server\s\S+) + \stransport + \stcp + \s(?P<tcp_port>port\s\d+) + $""", re.VERBOSE, + ), + "setval": "transport tcp port {{ transport.tcp.port }}", + "compval": "transport.tcp.port", + "result": { + "rpki": { + "servers": { + "{{rpki_server.split(" ")[1]}}": { + "transport": { + "tcp": { + "port": "{{ tcp_port.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_address", + "getval": re.compile( + r""" + \s+neighbor\s(?P<value>\S+) + $""", re.VERBOSE, + ), + "setval": "neighbor {{ neighbor_address }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{value}}": + { + "neighbor_address": "{{value}}", + }, + }, + }, + }, + }, + }, + { + "name": "advertisement_interval", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<advertise_in>advertisement-interval\s\d+) + $""", re.VERBOSE, + ), + "setval": "advertisement-interval {{ advertisement_interval }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "advertisement_interval": "{{ advertise_in.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "bfd_fast_detect_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbfd + \sfast-detect + \s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "bfd fast-detect disable", + "compval": "bfd.fast_detect.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "bfd": { + "fast_detect": {"disable": "{{ True if disable is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd_fast_detect_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbfd + \s(?P<fast_detect>fast-detect) + $""", re.VERBOSE, + ), + "setval": "bfd fast-detect", + "compval": "bfd.fast_detect.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "bfd": { + "fast_detect": {"set": "{{ True if fast_detect is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd_fast_detect_strict_mode", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbfd + \sfast-detect + \s(?P<strict_mode>strict-mode) + $""", re.VERBOSE, + ), + "setval": "bfd fast-detect strict-mode", + "compval": "bfd.fast_detect.strict_mode", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "bfd": { + "fast_detect": {"strict_mode": "{{ True if strict_mode is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd_nbr_multiplier", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbfd + \s(?P<multiplier>multiplier\s\S+) + $""", re.VERBOSE, + ), + "setval": "bfd multiplier {{ bfd.multiplier}}", + "compval": "bfd.multiplier", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": + { + "bfd": + { + "multiplier": "{{multiplier.split(" ")[1]}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd_nbr_minimum_interval", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbfd + \s(?P<min_interval>minimum-interval\s\S+) + $""", re.VERBOSE, + ), + "setval": "bfd minimum-interval {{ bfd.minimum_interval}}", + "compval": "bfd.minimum_interval", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": + { + "bfd": + { + "minimum_interval": "{{min_interval.split(" ")[1]}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bmp_activate", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbmp-activate + \s(?P<bmp_activate>server\s\d+) + $""", re.VERBOSE, + ), + "setval": "bmp-activate server {{bmp_activate.server}}", + "compval": "bmp_activate.serevr", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "bmp_activate": {"server": "{{ bmp_activate.split(" ")[1] }}"}, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_cluster_id", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<cluster_id>cluster-id\s\d+) + $""", re.VERBOSE, + ), + "setval": "cluster-id {{ cluster_id }}", + "compval": "cluster_id", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": {"cluster_id": "{{ cluster_id.split(" ")[1] }}"}, + }, + }, + }, + + }, + }, + { + "name": "neighbor_description", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sdescription\s(?P<description>.+) + $""", re.VERBOSE, + ), + "setval": "description {{ description }}", + "compval": "description", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": {"description": "{{ description }}"}, + }, + }, + }, + }, + }, + { + "name": "dmz_link_bandwidth", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<dmz_link_bandwidth>dmz-link-bandwidth) + $""", re.VERBOSE, + ), + "setval": "dmz-link-bandwidth", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": + { + "dmz_link_bandwidth": + { + "set": "{{ True if dmz_link_bandwidth is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "dmz_link_bandwidth_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sdmz-link-bandwidth + \s(?P<dmz_link_bandwidth>inheritance_disable) + $""", re.VERBOSE, + ), + "setval": "dmz-link-bandwidth inheritance-disable", + "compval": "dmz_link_bandwidth.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "dmz_link_bandwidth": + { + "inheritance_disable": "{{ True if dmz_link_bandwidth is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_multihop_value", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_multihop>ebgp-multihop\s\S+) + $""", re.VERBOSE, + ), + "setval": "ebgp-multihop {{ ebgp_multihop.value}}", + "compval": "ebgp_multihop.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_multihop": { + "value": "{{ ebgp_multihop.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_multihop_mpls", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_multihop>ebgp-multihop\s\S*\smpls) + $""", re.VERBOSE, + ), + "setval": "ebgp-multihop mpls", + "compval": "ebgp_multihop.mpls", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_multihop": {"mpls": "{{ True if ebgp_multihop is defined }}"}, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_recv_extcommunity_dmz", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_recv_extcommunity_dmz>ebgp-recv-extcommunity-dmz\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "ebgp-recv-extcommunity-dmz inheritance-disable ", + "compval": "ebgp_recv_extcommunity_dmz.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_recv_extcommunity_dmz": { + "inheritance_disable": "{{ True if ebgp_recv_extcommunity_dmz is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_recv_extcommunity_dmz_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_recv_extcommunity_dmz>ebgp-recv-extcommunity-dmz) + $""", re.VERBOSE, + ), + "setval": "ebgp-recv-extcommunity-dmz inheritance-disable", + "compval": "ebgp_recv_extcommunity_dm.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_recv_extcommunity_dmz": { + "set": "{{ True if ebgp_recv_extcommunity_dmz is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_send_extcommunity_dmz", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_send_extcommunity_dmz>ebgp-send-extcommunity-dmz\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "ebgp-send-extcommunity-dmz inheritance-disable ", + "compval": "ebgp_send_extcommunity_dmz.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_send_extcommunity_dmz": { + "inheritance_disable": "{{ True if ebgp_send_extcommunity_dmz is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_send_extcommunity_dmz_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_send_extcommunity_dmz>ebgp-send-extcommunity-dmz) + $""", re.VERBOSE, + ), + "setval": "ebgp-send-extcommunity-dmz", + "compval": "ebgp_send_extcommunity_dmz.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_send_extcommunity_dmz": { + "set": "{{ True if ebgp_send_extcommunity_dmz is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ebgp_send_extcommunity_dmz_cumulatie", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ebgp_send_extcommunity_dmz>ebgp-send-extcommunity-dmz\scumulatie) + $""", re.VERBOSE, + ), + "setval": "ebgp-send-extcommunity-dmz cumulatie ", + "compval": "ebgp_send_extcommunity_dmz.cumulatie", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ebgp_send_extcommunity_dmz": { + "cumulatie": "{{ True if ebgp_send_extcommunity_dmz is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "egress_engineering", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<egress_engineering>egress-engineering\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "egress-engineering inheritance-disable ", + "compval": "egress_engineering.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "egress_engineering": { + "inheritance_disable": "{{ True if egress_engineering is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "egress_engineering_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<egress_engineering>egress-engineering) + $""", re.VERBOSE, + ), + "setval": "egress-engineering", + "compval": "egress_engineering.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "egress_engineering": { + "set": "{{ True if egress_engineering is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_enforce_first_as_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<enforce_first_as_disable>enforce-first-as\sdisable) + $""", re.VERBOSE, + ), + "setval": "enforce-first-as disable", + "compval": "enforce_first_as.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "enforce_first_as": { + "disable": "{{ True if enforce_first_as_disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_restart_restart_time", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<graceful_restart_restart_time>graceful-restart\srestart-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "graceful-restart restart-time {{ graceful_restart.restart_time}}", + "compval": "graceful_restart.restart_time", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_restart": { + "restart_time": "{{ graceful_restart_restart_time.split(" ")[2] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_restart_stalepath_time", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<graceful_restart_stalepath_time>graceful-restart\sstalepath-time\s\d+) + $""", re.VERBOSE, + ), + "setval": "graceful-restart stalepath-time {{ graceful_restart.stalepath_time}}", + "compval": "graceful_restart.stalepath_time", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_restart": { + "stalepath_time": "{{ graceful_restart_stalepath_time.split(" ")[2] }}", + }, + }, + }, + }, + + }, + }, + }, + { + "name": "ignore_connected_check_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ignore_connected_check>ignore-connected-check) + $""", re.VERBOSE, + ), + "setval": "ignore-connected-check", + "compval": "ignore_connected_check.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ignore_connected_check": { + "set": "{{ True if ignore_connected_check is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "ignore_connected_check", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ignore_connected_check>ignore-connected-check\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "ignore-connected-check inheritance-disable ", + "compval": "ignore_connected_check.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ignore_connected_check": { + "inheritance_disable": "{{ True if ignore_connected_check is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "keychain", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<keychain>keychain\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "keychain inheritance-disable ", + "compval": "keychain.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "keychain": { + "inheritance_disable": "{{ True if keychain is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "keychain_name", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<keychain>keychain\s\S+) + $""", re.VERBOSE, + ), + "setval": "keychain {{ name }}", + "compval": "keychain.name", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "keychain": { + "name": "{{ keychain.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "remote_as", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<remote_as>remote-as\s\S+) + $""", re.VERBOSE, + ), + "setval": "remote-as {{ remote_as }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "remote_as": "{{ remote_as.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "local_as_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<local_as>local-as\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "local-as inheritance-disable", + "compval": "local_as.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "local_as": { + "inheritance_disable": "{{ True if local_as is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "local_as", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<local_as>local-as\s\S+) + $""", re.VERBOSE, + ), + "setval": "local-as {{ local_as.value }}", + "compval": "local_as.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "local_as": { + "value": "{{ local_as.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "local_address", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slocal + \s(?P<local>address\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "local address inheritance-disable", + "compval": "local.address.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "local": { + "address": { + "inheritance_disable": "{{ True if local is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "local", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slocal + \s(?P<local>address\s\S+) + $""", re.VERBOSE, + ), + "setval": "local address {{ local.address.ipv4_address }}", + "compval": "local.address.ipv4_address", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "local": { + "address": { + "ipv4_address": "{{ local.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "origin_as", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sorigin-as + \s(?P<origin_as>validation\sdisable) + $""", re.VERBOSE, + ), + "setval": "origin-as validation disable", + "compval": "origin-as.validation.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "origin_as": { + "validation": { + "disable": "{{ True if origin_as is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "receive_buffer_size", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<receive_buffer_size>receive-buffer-size\s\d+) + $""", re.VERBOSE, + ), + "setval": "receive-buffer-size {{ receive_buffer_size }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "receive_buffer_size": "{{ receive_buffer_size.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "send_buffer_size", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<send_buffer_size>send-buffer-size\s\d+) + $""", re.VERBOSE, + ), + "setval": "send-buffer-size {{ send_buffer_size }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "send_buffer_size": "{{ send_buffer_size.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "session_open_mode", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<session_open_mode>session-open-mode\s(active-only|both|passive-only)) + $""", re.VERBOSE, + ), + "setval": "session-open-mode {{ session_open_mode }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "session_open_mode": "{{ session_open_mode.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_shutdown", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<shutdown>shutdown) + $""", re.VERBOSE, + ), + "setval": "shutdown", + "compval": "shutdown", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "shutdown": { + "set": "{{ True if shutdown is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_shutdown_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<shutdown>shutdown\sinheritance_disable) + $""", re.VERBOSE, + ), + "setval": "shutdown inheritance-disable", + "compval": "shutdown.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "shutdown": {"inheritance_disable": "{{ True if shutdown is defined }}"}, + }, + }, + }, + }, + }, + }, + { + "name": "dscp", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<dscp>dscp\s\S+) + $""", re.VERBOSE, + ), + "setval": "dscp {{ dscp }}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "dscp": "{{ dscp.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_tcp_mss_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<tcp_mss_disable>tcp\smss\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "tcp mss inheritance-disable", + "compval": "tcp.mss.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "tcp": { + "mss": { + "inheritance_disable": "{{ True if tcp_mss_disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_tcp_mss", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<tcp_mss>tcp\smss\s\d+) + $""", re.VERBOSE, + ), + "setval": "tcp mss {{ tcp.mss.value }}", + "compval": "tcp.mss.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "tcp": { + "mss": { + "value": "{{ tcp_mss.split(" ")[2] }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_timers_keepalive", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<timers_keepalive_time>timers\s\d+) + \s(?P<timers_holdtime>\d+) + $""", re.VERBOSE, + ), + "setval": "timers {{ timers.keepalive_time}} {{ timers.holdtime }}", + "compval": "timers", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "timers": { + "keepalive_time": "{{ timers_keepalive_time.split(" ")[1] }}", + "holdtime": "{{ timers_holdtime.split(" ")[0] }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "update_source", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \supdate-source + \s(?P<update_source>\S+) + $""", re.VERBOSE, + ), + "setval": "update-source {{ update_source}}", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "update_source": "{{ update_source}}", + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_ttl_security_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ttl_security>ttl-security\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "ttl-security inheritance-disable", + "compval": "ttl_security.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ttl_security": { + "inheritance_disable": "{{ True if ttl_security is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_ttl_security", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<ttl_security>ttl-security) + $""", re.VERBOSE, + ), + "setval": "ttl-security", + "compval": "ttl_security.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "ttl_security": { + "set": "{{ True if ttl_security is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_set", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<graceful_maintenance>graceful-maintenance) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance", + "compval": "graceful_maintenance.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "set": "{{ True if graceful_maintenance is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_activate", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<graceful_maintenance>graceful-maintenance\sactivate) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance activate", + "compval": "graceful_maintenance.activate.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "activate": {"set": "{{ True if graceful_maintenance is defined }}"}, + }, + }, + }, + }, + }, + }, + }, + + { + "name": "neighbor_graceful_maintenance_activate_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<graceful_maintenance>activate\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance activate inheritance-disable", + "compval": "graceful_maintenance.activate.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "activate": { + "inheritance_disable": "{{ True if graceful_maintenance is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_as_prepends", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<as_prepends>as-prepends\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance as-prepends inheritance-disable", + "compval": "graceful_maintenance.as_prepends.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "as_prepends": { + "inheritance_disable": "{{ True if as_prepends is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_local_preference_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<local_preference>local-preference\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance local-preference inheritance-disable", + "compval": "graceful_maintenance.local_preference.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "local_preference": { + "inheritance_disable": "{{ True if local_preference is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_local_preference", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<local_preference>local-preference\s\d+) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance local-preference {{ graceful_maintenance.local_preference.value}}", + "compval": "graceful_maintenance.local_preference.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "local_preference": { + "value": "{{ local_preference.split(" ")[1]}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_graceful_maintenance_as_prepends_value", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<as_prepends>as-prepends\s\d+) + $""", re.VERBOSE, + ), + "setval": "graceful-maintenance as-prepends {{ graceful_maintenance.as_prepends.value }}", + "compval": "graceful_maintenance.as_prepends.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "graceful_maintenance": { + "as_prepends": { + "value": "{{ as_prepends.split(" ")[1]}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_additional_paths_send", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \sadditional-paths + \s(?P<additional_paths_send>send) + $""", re.VERBOSE, + ), + "setval": "capability additional-paths send", + "compval": "capability.additional_paths.send.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "additional_paths": { + "send": { + "set": "{{ True if additional_paths_send is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_additional_paths_send_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \sadditional-paths + \s(?P<additional_paths_send>send\sdisable) + $""", re.VERBOSE, + ), + "setval": "capability additional-paths send disable", + "compval": "capability.additional_paths.send.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "additional_paths": { + "send": { + "disable": "{{ True if additional_paths_send is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_additional_paths_rcv", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \sadditional-paths + \s(?P<additional_paths_receive>receive) + $""", re.VERBOSE, + ), + "setval": "capability additional-paths receive", + "compval": "capability.additional_paths.receive.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "additional_paths": { + "receive": { + "set": "{{ True if additional_paths_receive is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_additional_paths_rcv_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \sadditional-paths + \s(?P<additional_paths_receive_disable>receive\sdisable) + $""", re.VERBOSE, + ), + "setval": "capability additional-paths receive disable", + "compval": "capability.additional_paths.receive.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "additional_paths": { + "receive": { + "disable": "{{ True if additional_paths_receive_disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_suppress_four_byte_AS", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \ssuppress + \s(?P<suppress_4_byte_as>4-byte-as) + $""", re.VERBOSE, + ), + "setval": "capability suppress 4-byte-as", + "compval": "capability.suppress.four_byte_AS.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "suppress": { + "four_byte_AS": { + "set": "{{ True if suppress_4_byte_as is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_suppress_all", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \ssuppress + \s(?P<all>all) + $""", re.VERBOSE, + ), + "setval": "capability suppress all", + "compval": "capability.suppress.all.set", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "suppress": { + "all": { + "set": "{{ True if all is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_capability_suppress_all_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \scapability + \ssuppress + \s(?P<all>all\sinheritance-disable) + $""", re.VERBOSE, + ), + "setval": "capability suppress all inheritance-disable", + "compval": "capability.suppress.all.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "capability": { + "suppress": { + "all": { + "inheritance_disable": "{{ True if all is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + + { + "name": "neighbor_log_message_in_value", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<value>in\s\d+) + $""", re.VERBOSE, + ), + "setval": "log message in {{ log.message.in.value}}", + "compval": "log.log_message.in.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "in": { + "value": "{{ value.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_log_message_in_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<disable>in\sdisable) + $""", re.VERBOSE, + ), + "setval": "log message in disable", + "compval": "log.log_message.in.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "in": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_log_message_in_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<disable>in\sinheritance-diable) + $""", re.VERBOSE, + ), + "setval": "log message in inheritance-diable", + "compval": "log.log_message.in.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "in": { + "inheritance_disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_log_message_out_value", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<value>out\s\d+) + $""", re.VERBOSE, + ), + "setval": "log message out {{ log.message.out.value}}", + "compval": "log.log_message.out.value", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "out": { + "value": "{{ value.split(" ")[1] }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_log_message_out_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<disable>out\sdisable) + $""", re.VERBOSE, + ), + "setval": "log message out disable", + "compval": "log.log_message.out.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "out": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_log_message_out_inheritance_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \slog + \smessage + \s(?P<disable>out\sinheritance-diable) + $""", re.VERBOSE, + ), + "setval": "log message out inheritance-diable", + "compval": "log.log_message.out.inheritance_disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "log": { + "log_message": { + "out": { + "inheritance_disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_update_in_filtering_attribute_filter_group", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<attribute_filter_group>attribute-filter\sgroup\s\S+) + $""", re.VERBOSE, + ), + "setval": "update in filtering attribute-filter group {{ update.in.filtering.attribute_filter.group }}", + "compval": "update.in.filtering.attribute_filter.group", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "update": { + "in": { + "filtering": { + "attribute_filter": { + "group": "{{ attribute_filter_group.split(" ")[2] }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_update_in_filtering_logging_disable", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<logging_disable>logging\sdisable) + $""", re.VERBOSE, + ), + "setval": "update in filtering logging disable", + "compval": "update.in.filtering.logging.disable", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "update": { + "in": { + "filtering": { + "logging": { + "disable": "{{True if logging_disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "neighbor_update_in_filtering_message_buffers", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \s(?P<message_buffers>message\sbuffers\s\d+) + $""", re.VERBOSE, + ), + "setval": "update in filtering message buffers {{ update.in.filtering.message.buffers}}", + "compval": "update.in.filtering.update_message.buffers", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "update": { + "in": { + "filtering": { + "update_message": { + "buffers": "{{ message_buffers.split(" ")[2] }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "rd_auto", + "getval": re.compile( + r""" + \s+rd(?P<rd_auto>\sauto) + $""", re.VERBOSE, + ), + "setval": "rd auto", + "compval": "rd.auto", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "rd": { + "auto": "{{True if rd_auto is defined }}", + }, + }, + }, + }, + }, + { + "name": "timers_keepalive", + "getval": re.compile( + r""" + \s+timers\sbgp\s(?P<timers_keepalive_time>\d+)\s(?P<hold_time>\d+) + $""", re.VERBOSE, + ), + "setval": "timers bgp {{ timers.keepalive_time}} {{ timers.holdtime}}", + "compval": "timers", + "result": { + "vrfs": { + '{{ "vrf_" + vrf|d() }}': { + "timers": { + "keepalive_time": "{{ timers_keepalive_time }}", + "holdtime": "{{ hold_time}}", + }, + }, + }, + }, + }, + + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_neighbor_address_family.py new file mode 100644 index 00000000..3d12e882 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/bgp_neighbor_address_family.py @@ -0,0 +1,1038 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Bgp_neighbor_address_family parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def _tmpl_aigp(config_data): + conf = config_data.get("aigp", {}) + commands = [] + if conf: + if "set" in conf: + commands.append("aigp") + if "disable" in conf: + commands.append("aigp disable") + if "send_cost_community_disable" in conf: + commands.append("aigp send cost-community disable") + if "send_med" in conf and "set" in conf.get("send_med", {}): + commands.append("aigp send med") + if "send_med" in conf and "disable" in conf.get("send_med", {}): + commands.append("aigp send med disable") + return commands + + +def _tmpl_validation(config_data): + conf = config_data.get("validation", {}) + command = "" + if conf: + if "set" in conf: + command = "validation" + if "disable" in conf: + command = "validation disbale" + if "redirect" in conf: + command = "validation redirect" + return command + + +def _tmpl_next_hop_unchanged(config_data): + conf = config_data.get("next_hop_unchanged", {}) + command = "" + if conf: + if "set" in conf: + command = "next-hop-unchanged" + if "inheritance_disable" in conf: + command += "next-hop-unchanged inheritance-disable" + if "multipath" in conf: + command = "next-hop-unchanged multipath" + return command + + +def _tmpl_maximum_prefix(config_data): + conf = config_data.get("maximum_prefix", {}) + if conf: + command = "maximum-prefix" + if "max_limit" in conf: + command += " " + str(conf["max_limit"]) + if "threshold_value" in conf: + command += " " + str(conf["threshold_value"]) + if "restart" in conf: + command += " restart " + str(conf["restart"]) + elif "warning_only" in conf: + command += " warning-only" + elif "discard_extra_paths" in conf: + command += " discard-extra-paths" + + return command + + +def _tmpl_soft_reconfiguration(config_data): + conf = config_data.get("soft_reconfiguration", {}) + if conf: + command = "soft-reconfiguration " + if "inbound" in conf: + command += "inbound" + if "set" in conf["inbound"]: + pass + elif "always" in conf["inbound"]: + command += " always" + if "inheritance_disable" in conf["inbound"]: + command += " inheritance-disable" + + return command + + +def _tmpl_remove_private_AS(config_data): + conf = config_data.get("remove_private_AS", {}) + if conf: + command = " " + if "set" in conf: + command = "remove-private-AS" + if "inbound" in conf: + command += " inbound" + if "entire_aspath" in conf: + command += " entire-aspath" + elif "inheritance_disable" in conf: + command = "remove-private-AS inheritance-disable" + return command + + +def _tmpl_default_originate(config_data): + conf = config_data.get("default_originate", {}) + command = "" + if conf: + if "set" in conf: + command = "default-originate" + if "inheritance_disable" in conf: + command = "default-originate inheritance-disable" + if "route_policy" in conf: + command = "default-originate route_policy " + conf["route_policy"] + return command + + +class Bgp_neighbor_address_familyTemplate(NetworkTemplate): + def __init__(self, lines=None): + super(Bgp_neighbor_address_familyTemplate, self).__init__( + lines=lines, + tmplt=self, + ) + + # fmt: off + PARSERS = [ + { + "name": "router", + "getval": re.compile( + r""" + ^router\s + bgp + \s(?P<as_num>\S+) + $""", + re.VERBOSE, + ), + "setval": "router bgp {{ as_number }}", + "compval": "as_number", + "result": {"as_number": "{{ as_num }}"}, + "shared": True, + }, + { + "name": "address_family", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + (\s+(?P<nbr_address>neighbor\s\S+)) + (?P<address_family>\s+address-family\s(?P<afi>\S+)\s(?P<safi>\S+)) + $""", re.VERBOSE, + ), + "setval": "address-family {{ afi}} {{safi}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "neighbor_address": "{{nbr_address.split(" ")[1]}}", + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "afi": "{{ afi}}", + "safi": "{{safi}}", + }, + }, + }, + }, + }, + }, + }, + "shared": True, + }, + { + "name": "aigp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \saigp(?P<aigp>) + (\sdisable(?P<disable>))? + (\ssend\smed(?P<send_med>))? + (\ssend\smed\sdisable(?P<send_disable>))? + (\ssend\scost-community\sdisable(?P<cc_disable>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_aigp, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "aigp": { + "set": "{{ True if aigp is defined }}", + "disable": "{{ True if disable is defined}}", + "send_med": { + "set": "{{ True if send_med is defined }}", + "disable": "{{ True if send_disable is defined}}", + }, + "send_cost_community_disable": "{{True if cc_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "allowas_in", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sallowas-in(?P<allowas_in>)(\s(?P<value>\S+))? + $""", re.VERBOSE, + ), + "setval": "allowas-in {{allowas_in.value if allowas_in.value is defined }}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "allowas_in": { + "set": "{{True if allowas_in is defined and value is not defined}}", + "value": "{{value }}", + }, + }, + }, + }, + }, + }, + }, + }, + + }, + { + "name": "as_override", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sas-override(?P<as_override>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "as-override{{' inheritance-disable' if as_override.inheritance_disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "as_override": { + "set": "{{True if as_override is defined " + "and inheritance_disable is not defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bestpath_origin_as_allow_invalid", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sbestpath\sorigin-as\sallow\sinvalid(?P<invalid>) + $""", re.VERBOSE, + ), + "setval": "bestpath origin-as allow invalid", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "bestpath_origin_as_allow_invalid": "{{ True if invalid is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "capability_orf_prefix", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \scapability\sorf\sprefix\s(?P<capability_orf_prefix>\S+) + $""", re.VERBOSE, + ), + "setval": "capability orf prefix {{capability_orf_prefix }}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "capability_orf_prefix": "{{capability_orf_prefix}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "default_originate", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sdefault-originate(?P<default_originate>) + (\sroute-policy\s(?P<route_policy>\S+))? + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_default_originate, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi}}': { + "default_originate": { + "set": "{{True if default_originate is defined}}", + "route_policy": "{{route_policy}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "long_lived_graceful_restart_capable", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \s+long-lived-graceful-restart + \s(?P<capable>capable) + $""", re.VERBOSE, + ), + "setval": "long-lived-graceful-restart capable", + "compval": "long_lived_graceful_restart.capable", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "long_lived_graceful_restart": { + "capable": "{{True if capable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "long_lived_graceful_restart_stale_time", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \s+long-lived-graceful-restart + \s+stale-time\ssend\s(?P<stale_time_send>\d+)\saccept\s(?P<accept>\d+) + $""", re.VERBOSE, + ), + "setval": "long-lived-graceful-restart stale-time send " + "{{stale_time.send}} accept {{stale_time.accept}}", + "compval": "long_lived_graceful_restart.stale_time", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "long_lived_graceful_restart": { + "stale_time": { + "send": "{{stale_time_send}}", + "accept": "{{accept}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "maximum_prefix", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \s+maximum-prefix + (\s(?P<maximum_prefix>\d+))? + (\s(?P<threshold_value>\d+))? + (\srestart\s(?P<restart>\d+))? + (\swarning-only\s(?P<warning_only>))? + (\sdiscard-extra-paths\s(?P<discard_extra_paths>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_maximum_prefix, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "maximum_prefix": { + "max_limit": "{{maximum_prefix}}", + "threshold_value": "{{threshold_value}}", + "restart": "{{restart}}", + "warning_only": "{{ True if warning_only is defined}}", + "discard_extra_paths": "{{ True if discard_extra_paths is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "multipath", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \smultipath(?P<multipath>) + $""", re.VERBOSE, + ), + "setval": "multipath", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "multipath": "{{True if multipath is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "next_hop_self", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \snext-hop-self(?P<next_hop_self>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "next-hop-self{{' inheritance-disable' if next_hop_self.inheritance_disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "next_hop_self": { + "set": "{{True if next_hop_self is defined and" + " inheritance_disable is not defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "next_hop_unchanged", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \snext-hop-unchanged(?P<next_hop_unchanged>) + (\sinheritance-disable(?P<inheritance_disable>))? + (\smultipath(?P<multipath>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_next_hop_unchanged, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi}}': { + "next_hop_unchanged": { + "set": "{{True if next_hop_self is defined }}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + "multipath": "{{True if multipath is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "optimal_route_reflection_group_name", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \soptimal-route-reflection\s(?P<group_name>\S+) + $""", re.VERBOSE, + ), + "setval": "optimal-route-reflection {{optimal_route_reflection_group_name}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "optimal_route_reflection_group_name": "{{ group_name}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "orf_route_policy", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sorf\sroute-policy\s(?P<orf_rr>\S+) + $""", re.VERBOSE, + ), + "setval": "orf route-policy {{orf_route_policy}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "orf_route_policy": "{{orf_rr}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "origin_as", + "getval": re.compile( + r""" + \s+(?P<nbr_address>neighbor\s\S+) + \sorigin-as\svalidation\sdisable(?P<origin_as>) + $""", re.VERBOSE, + ), + "setval": "origin-as validation disable", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "origin_as": { + "validation": { + "disable": "{{True if origin_as is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_policy.inbound", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sroute-policy\s(?P<route_policy>\S+) + \sin + $""", re.VERBOSE, + ), + "setval": "route-policy {{route_policy.inbound}} in", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "route_policy": { + "inbound": "{{route_policy}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_policy.outbound", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sroute-policy\s(?P<route_policy>\S+) + \sout + $""", re.VERBOSE, + ), + "setval": "route-policy {{route_policy.outbound}} out", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "route_policy": { + "outbound": "{{route_policy}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "remove_private_AS", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sremove-private-AS(?P<remove_private_AS>) + (\sinbound(?P<inbound>))? + (\sentire-aspath(?P<entire_aspath>))? + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_remove_private_AS, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "remove_private_AS": { + "set": "{{True if remove_private_AS is defined}}", + "inbound": "{{True if inbound is defined}}", + "entire_aspath": "{{True if entire_aspath is defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_reflector_client", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sroute-reflector-client(?P<route_reflector_client>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "route-reflector-client{{' inheritance-disable' " + "if route_reflector_client.inheritance_disable is defined }}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "route_reflector_client": { + "set": "{{True if route_reflector_client is defined and " + "inheritance_disable is not defined }}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "send_community_ebgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \ssend-community-ebgp(?P<send_community_ebgp>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "send-community-ebgp{{' inheritance-disable' " + "if send_community_ebgp.inheritance_disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "send_community_ebgp": { + "set": "{{True if send_community_ebgp is defined and " + "inheritance_disable is not defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "send_community_gshut_ebgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \ssend-community-gshut-ebgp(?P<send_community_gshut_ebg>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "send-community-gshut-ebgp{{' inheritance-disable' " + "if send_community_gshut_ebgp.inheritance_disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "send_community_gshut_ebgp": { + "set": "{{True if send_community_gshut_ebg is defined and " + "inheritance_disable is not defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "send_extended_community_ebgp", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \ssend-extended-community-ebgp(?P<send_extended_community_ebgp>) + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": "send-extended-community-ebgp{{' inheritance-disable' " + "if send_extended_community_ebgp.inheritance_disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "send_extended_community_ebgp": { + "set": "{{True if send_extended_community_ebgp is defined and " + "inheritance_disable is not defined}}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "send_multicast_attributes", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \s+(?P<send_multicast_attributes>send-multicast-attributes) + (\sdisable(?P<disable>))? + $""", re.VERBOSE, + ), + "setval": "send-multicast-attributes{{' disable' " + "if send_multicast_attributes.disable is defined else ''}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "send_multicast_attributes": { + "set": "{{True if send_multicast_attributes is " + "defined and disable is not defined}}", + "disable": "{{True if disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "soft_reconfiguration", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \ssoft-reconfiguration + \sinbound(?P<inbound>) + (\salways(?P<always>))? + (\sinheritance-disable(?P<inheritance_disable>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_soft_reconfiguration, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "soft_reconfiguration": { + "inbound": { + "set": "{{True if inbound is defined and " + "inheritance_disable is not defined and " + "always is not defined}}", + "always": "{{True if always is defined }}", + "inheritance_disable": "{{True if inheritance_disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "weight", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \sweight\s(?P<weight>\d+) + $""", re.VERBOSE, + ), + "setval": "weight {{weight}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "weight": "{{weight}}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "validation", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \svalidation(?P<validation>) + (\sredirect(?P<redirect>))? + (\sdisable(?P<disable>))? + $""", re.VERBOSE, + ), + "setval": _tmpl_validation, + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "validation": { + "set": "{{True if validation is defined}}", + "redirect": "{{True if redirect is defined }}", + "disable": "{{ True if disable is defined}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "site_of_origin", + "getval": re.compile( + r""" + (\s+vrf\s(?P<vrf>\S+))? + \s+(?P<nbr_address>neighbor\s\S+) + \ssite-of-origin\s(?P<site_of_origin>\S+) + $""", re.VERBOSE, + ), + "setval": "site-of-origin {{site_of_origin}}", + "result": { + "vrfs": { + "{{ 'vrf_' + vrf|d() }}": { + "vrf": "{{ vrf }}", + "neighbors": { + "{{nbr_address.split(" ")[1]}}": { + "address_family": { + '{{"address_family_" + afi + "_" + safi }}': { + "site_of_origin": "{{site_of_origin}}", + }, + }, + }, + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/hostname.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/hostname.py new file mode 100644 index 00000000..1be361fe --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/hostname.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Hostname parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class HostnameTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(HostnameTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "hostname", + "getval": re.compile( + r""" + ^hostname\s(?P<hostname>\S+) + $""", re.VERBOSE, + ), + "setval": "hostname {{ hostname }}", + "result": { + "hostname": "{{ hostname }}", + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/logging_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/logging_global.py new file mode 100644 index 00000000..90d78d77 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/logging_global.py @@ -0,0 +1,866 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Logging_global parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def tmplt_host(config_data): + command = "logging" + if config_data.get("host"): + command += " {host}".format(host=config_data["host"]) + if config_data.get("vrf"): + command += " vrf {vrf}".format(vrf=config_data["vrf"]) + if config_data.get("severity"): + command += " severity {severity}".format( + severity=config_data["severity"], + ) + if config_data.get("port"): + command += " port {port}".format(port=config_data["port"]) + return command + + +def tmplt_correlator_rule(config_data): + commands = [] + rule_name = config_data.get("rule_name") + rule_type = config_data.get("rule_type") + base_command = "logging correlator rule {rule_name} type {rule_type}".format( + rule_type=rule_type, + rule_name=rule_name, + ) + if config_data.get("timeout"): + commands.append( + "{base_command} timeout {timeout}".format( + timeout=config_data["timeout"], + base_command=base_command, + ), + ) + if config_data.get("timeout_rootcause"): + commands.append( + "{base_command} timeout-rootcause {timeout}".format( + timeout=config_data["timeout_rootcause"], + base_command=base_command, + ), + ) + if config_data.get("reissue_nonbistate"): + commands.append( + "{base_command} reissue-nonbistate".format( + base_command=base_command, + ), + ) + if config_data.get("reparent"): + commands.append( + "{base_command} reparent".format(base_command=base_command), + ) + if config_data.get("context_correlation"): + commands.append( + "{base_command} context-correlation".format( + base_command=base_command, + ), + ) + return commands + + +def tmplt_correlator_ruleset(config_data): + command = "logging correlator ruleset" + if config_data.get("name"): + command += " {name}".format(name=config_data["name"]) + if config_data.get("rulename"): + command += " rulename {rulename}".format( + rulename=config_data["rulename"], + ) + return command + + +def tmplt_files(config_data): + command = "logging" + if config_data.get("name"): + command += " file {name}".format(name=config_data["name"]) + if config_data.get("path"): + command += " path {path}".format(path=config_data["path"]) + if config_data.get("maxfilesize"): + command += " maxfilesize {maxfilesize}".format( + maxfilesize=config_data["maxfilesize"], + ) + if config_data.get("severity"): + command += " severity {severity}".format( + severity=config_data["severity"], + ) + return command + + +def tmplt_source_interface(config_data): + command = "logging source-interface" + if config_data.get("interface"): + command += " {interface}".format(interface=config_data["interface"]) + if config_data.get("vrf"): + command += " vrf {vrf}".format(vrf=config_data["vrf"]) + return command + + +def tmplt_tls_servers(config_data): + commands = [] + name = config_data.get("name") + base_command = "logging tls-server {name}".format(name=name) + if config_data.get("tls_hostname"): + commands.append( + "{base_command} tls-hostname {tls}".format( + tls=config_data["tls_hostname"], + base_command=base_command, + ), + ) + if config_data.get("trustpoint"): + commands.append( + "{base_command} trustpoint {trustpoint}".format( + trustpoint=config_data["trustpoint"], + base_command=base_command, + ), + ) + if config_data.get("vrf"): + commands.append( + "{base_command} vrf {vrf}".format( + vrf=config_data["vrf"], + base_command=base_command, + ), + ) + if config_data.get("severity"): + commands.append( + "{base_command} severity {severity}".format( + severity=config_data["severity"], + base_command=base_command, + ), + ) + if len(commands) == 0: + commands.append(base_command) + return commands + + +def rem_tmplt_tls_servers(config_data): + command = "logging tls-server" + if config_data.get("name"): + command += " {name}".format(name=config_data["name"]) + return command + + +class Logging_globalTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Logging_globalTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "archive.device", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+device\s(?P<device>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging archive device {{archive.device}}", + "result": { + "archive": { + "device": "{{ device }}", + }, + }, + }, + { + "name": "archive.severity", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+severity\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings)) + $""", re.VERBOSE, + ), + "setval": "logging archive severity {{archive.severity}}", + "result": { + "archive": { + "severity": "{{severity}}", + }, + }, + }, + { + "name": "archive.file_size", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+file-size\s(?P<file_size>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging archive file-size {{archive.file_size}}", + "result": { + "archive": { + "file_size": "{{ file_size }}", + }, + }, + }, + { + "name": "archive.frequency", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+frequency\s(?P<frequency>daily|weekly))? + $""", re.VERBOSE, + ), + "setval": "logging archive frequency {{archive.frequency}}", + "result": { + "archive": { + "frequency": "{{ frequency }}", + }, + }, + }, + { + "name": "archive.archive_size", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+archive-size\s(?P<archive_size>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging archive archive-size {{archive.archive_size}}", + "result": { + "archive": { + "archive_size": "{{ archive_size }}", + }, + }, + }, + { + "name": "archive.archive_length", + "getval": re.compile( + r""" + ^logging\sarchive + (\s+archive-length\s(?P<archive_length>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging archive archive-length {{archive.archive_length}}", + "result": { + "archive": { + "archive_length": "{{ archive_length}}", + }, + }, + }, + { + "name": "hosts", + "getval": re.compile( + r""" + ^logging + (\s(?P<host>\S+))? + (\svrf\s(?P<vrf>\w+))? + (\sseverity\s(?P<severity>alerts|critical|debugging|emergencies|error|informational|notifications|warnings))? + (\sport\s(?P<port>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_host, + "result": { + "hosts": [{ + "host": "{{ host }}", + "port": "{{ port }}", + "vrf": "{{ vrf }}", + "severity": "{{severity}}", + }], + }, + + }, + { + "name": "buffered.size", + "getval": re.compile( + r""" + ^logging\sbuffered + (\s(?P<size>[1-9][0-9]*))? + $""", re.VERBOSE, + ), + "setval": "logging buffered {{buffered.size}}", + "result": { + "buffered": { + "size": "{{ size }}", + }, + + }, + }, + { + "name": "buffered.severity", + "getval": re.compile( + r""" + ^logging\sbuffered + (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))? + $""", re.VERBOSE, + ), + "setval": "logging buffered {{buffered.severity}}", + "result": { + + "buffered": { + "severity": "{{ severity }}", + }, + }, + + }, + { + "name": "buffered.discriminator", + "getval": re.compile( + r""" + ^logging\sbuffered\sdiscriminator + \s+(?P<match_nomatch>\S+)\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "logging buffered discriminator {{match_params}} {{name}}", + "result": { + "buffered": { + "discriminator": [ + { + "match_params": "{{ match_nomatch }}", + "name": "{{name}}", + }, + ], + }, + + }, + }, + { + "name": "console.severity", + "getval": re.compile( + r""" + ^logging\sconsole + (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warning$))? + $""", re.VERBOSE, + ), + "setval": "logging console {{console.severity}}", + "result": { + "console": { + "severity": "{{ severity }}", + }, + }, + }, + { + "name": "console.state", + "getval": re.compile( + r""" + ^logging\sconsole + \s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "{{ 'logging console disable' if console.state =='disabled' else 'no logging console disable' }}", + "result": { + "console": { + "state": "{{ 'disabled' if disable is defined }}", + }, + }, + }, + { + "name": "console.discriminator", + "getval": re.compile( + r""" + ^logging\sconsole\sdiscriminator + \s+(?P<match_nomatch>\S+)\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "logging console discriminator {{match_params}} {{name}}", + "result": { + "console": { + "discriminator": [ + { + "match_params": "{{ match_nomatch }}", + "name": "{{name}}", + }, + ], + }, + }, + }, + { + "name": "correlator.buffer_size", + "getval": re.compile( + r""" + ^logging\scorrelator + (\sbuffer-size\s(?P<buffer_size>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging correlator buffer-size {{correlator.buffer_size }}", + "result": { + "correlator": { + "buffer_size": "{{ buffer_size }}", + }, + }, + }, + { + "name": "correlator.rules", + "getval": re.compile( + r""" + ^logging\scorrelator + (\srule\s(?P<name>\S+))? + (\stype\s(?P<rule_type>\S+))? + (\s+reissue-nonbistate(?P<reissue_nonbistate>))? + (\s+timeout\s(?P<timeout>\S+))? + (\s+reparent(?P<reparent>))? + (\s+context-correlation(?P<context_correlation>))? + (\s+timeout-rootcause\s(?P<timeout_rootcause>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_correlator_rule, + "result": { + "correlator": { + "rules": { + "{{name}}": { + "rule_name": "{{ name }}", + "rule_type": "{{ rule_type }}", + "reissue_nonbistate": "{{ True if reissue_nonbistate is defined }}", + "timeout": "{{ timeout }}", + "reparent": "{{ True if reparent is defined }}", + "context_correlation": "{{ True if context_correlation is defined }}", + "timeout_rootcause": "{{ timeout_rootcause }}", + + }, + }, + }, + }, + }, + { + "name": "correlator.rule_sets", + "getval": re.compile( + r""" + ^logging\scorrelator\sruleset\s(?P<name>\S+) + (\srulename\s(?P<rulename>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_correlator_ruleset, + "result": { + "correlator": { + "rule_sets": { + "{{name}}": { + "name": "{{ name }}", + "rulename": ["{{ rulename }}"], + + }, + }, + }, + }, + }, + { + "name": "events.threshold", + "getval": re.compile( + r""" + ^logging\sevents + (\sthreshold\s(?P<threshold>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging events threshold {{events.threshold}}", + "result": { + "events": + {"threshold": "{{ threshold }}"}, + }, + + }, + { + "name": "events.buffer_size", + "getval": re.compile( + r""" + ^logging\sevents + (\sbuffer-size\s(?P<buffer_size>\S+))? + $""", re.VERBOSE, + ), + "setval": "logging events buffer-size {{events.buffer_size}}", + "result": { + "events": {"buffer_size": "{{ buffer_size }}"}, + }, + + }, + { + "name": "events.display_location", + "getval": re.compile( + r""" + ^logging\sevents + (\sdisplay-location(?P<display_location>))? + $""", re.VERBOSE, + ), + "setval": "logging events display-location", + "result": { + "events": + { + "display_location": "{{ True if display_location is defined }}", + + }, + + }, + }, + { + "name": "events.filter_match", + "getval": re.compile( + r""" + ^logging\sevents\sfilter + (\s+match\s(?P<match>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging events filter match {{match}}", + "result": { + "events": { + "filter_match": [ + "{{ match }}", + ], + }, + }, + }, + { + "name": "events.severity", + "getval": re.compile( + r""" + ^logging\sevents + (\slevel\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))? + $""", re.VERBOSE, + ), + "setval": "logging events level {{events.severity}}", + "result": { + "events": + { + "severity": "{{ severity }}", + + }, + }, + }, + { + "name": "files", + "getval": re.compile( + r""" + ^logging + (\sfile\s(?P<file>\S+))? + (\spath\s(?P<path>\S+))? + (\smaxfilesize\s(?P<maxfilesize>\S+))? + (\sseverity\s(?P<severity>alerts|critical|debugging|emergencies|errors|info|notifications|warning))? + $""", re.VERBOSE, + ), + "setval": tmplt_files, + "result": { + "files": [ + { + "name": "{{file}}", + "path": "{{path}}", + "maxfilesize": "{{maxfilesize}}", + "severity": "{{ severity }}", + + }, + ], + }, + }, + { + "name": "facility", + "getval": re.compile( + r""" + ^logging\sfacility + \s(?P<facility>auth|cron|daemon|kern|local0|local1|local2|local3|local4|local5|local6|local7|lpr|mail|news|sys10|sys11|sys12|sys13|sys14|sys9|syslog|user|uucp) + $""", re.VERBOSE, + ), + "setval": "logging facility {{ facility }}", + "result": { + "facility": "{{ facility }}", + }, + }, + { + "name": "format", + "getval": re.compile( + r""" + ^logging\sformat + (\srfc5424(?P<format>)) + $""", re.VERBOSE, + ), + "setval": "logging format rfc5424", + "result": { + "format": "{{True if format is defined}}", + }, + }, + { + "name": "hostnameprefix", + "getval": re.compile( + r""" + ^logging + (\shostnameprefix\s(?P<hostnameprefix>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging hostnameprefix {{hostnameprefix}}", + "result": { + "hostnameprefix": "{{hostnameprefix}}", + }, + }, + { + "name": "ipv4.dscp", + "getval": re.compile( + r""" + ^logging + \sipv4\sdscp\s(?P<dscp>\S+) + $""", re.VERBOSE, + ), + "setval": "logging ipv4 dscp {{ipv4.dscp}}", + "result": { + "ipv4": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv6.dscp", + "getval": re.compile( + r""" + ^logging + (\sipv6\sdscp\s(?P<dscp>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging ipv6 dscp {{ipv6.dscp}}", + "result": { + "ipv6": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv4.precedence", + "getval": re.compile( + r""" + ^logging + (\sipv4\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging ipv4 precedence {{ipv4.precedence}}", + "result": { + "ipv4": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "ipv6.precedence", + "getval": re.compile( + r""" + ^logging + (\sipv6\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging ipv6 precedence {{ipv6.precedence}}", + "result": { + "ipv6": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "localfilesize", + "getval": re.compile( + r""" + ^logging + (\slocalfilesize\s(?P<localfilesize>\S+)) + $""", re.VERBOSE, + ), + "setval": "logging localfilesize {{localfilesize}}", + "result": { + "localfilesize": "{{localfilesize}}", + }, + }, + { + "name": "suppress.duplicates", + "getval": re.compile( + r""" + ^logging + (\ssuppress\sduplicates(?P<suppress_duplicates>)) + $""", re.VERBOSE, + ), + "setval": "logging suppress duplicates", + "result": { + "suppress": + {"duplicates": "{{True if suppress_duplicates is defined}}"}, + }, + }, + { + "name": "suppress.apply_rule", + "getval": re.compile( + r""" + ^logging\ssuppress\sapply\srule\s(?P<apply_rules>\S+) + $""", re.VERBOSE, + ), + "setval": "logging suppress apply rule {{suppress.apply_rule}}", + "result": { + "suppress": {"apply_rule": "{{apply_rules}}"}, + }, + }, + { + "name": "history.size", + "getval": re.compile( + r""" + ^logging\shistory + (\ssize\s(?P<size>\d+)) + $""", re.VERBOSE, + ), + "setval": "logging history size {{history.size}}", + "result": { + "history": { + "severity": "{{ severity }}", + "size": "{{ size }}", + }, + }, + }, + { + "name": "history.severity", + "getval": re.compile( + r""" + ^logging\shistory + (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warning)) + $""", re.VERBOSE, + ), + "setval": "logging history {{history.severity}}", + "result": { + "history": { + "severity": "{{ severity }}", + }, + }, + }, + { + "name": "history.state", + "getval": re.compile( + r""" + ^logging\shistory + \s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "{{ 'logging history disable' if history.state =='disabled' else 'no logging history disable' }}", + "result": { + "history": { + "state": "{{ 'disabled' if disable is defined }}", + }, + }, + }, + { + "name": "monitor.severity", + "getval": re.compile( + r""" + ^logging\smonitor + (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warning))? + $""", re.VERBOSE, + ), + "setval": "logging monitor {{monitor.severity}}", + "result": { + "monitor": { + "severity": "{{ severity }}", + }, + }, + }, + { + "name": "monitor.state", + "getval": re.compile( + r""" + ^logging\smonitor\s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "{{ 'logging monitor disable' if monitor.state =='disabled' else 'no logging monitor disable' }}", + "result": { + "monitor": { + "state": "{{ 'disabled' if disable is defined }}", + }, + }, + }, + { + "name": "monitor.discriminator", + "getval": re.compile( + r""" + ^logging\smonitor\sdiscriminator + \s+(?P<match_nomatch>\S+)\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "logging monitor discriminator {{match_params}} {{name}}", + "result": { + "monitor": { + "discriminator": [ + { + "match_params": "{{ match_nomatch }}", + "name": "{{name}}", + }, + ], + }, + + }, + }, + { + "name": "source_interfaces", + "getval": re.compile( + r""" + ^logging\ssource-interface + (\s(?P<interface>\S+))? + (\svrf\s(?P<vrf>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_source_interface, + "result": { + "source_interfaces": [ + { + "interface": "{{ interface }}", + "vrf": "{{ vrf }}", + }, + ], + }, + }, + { + "name": "trap.severity", + "getval": re.compile( + r""" + ^logging\strap + \s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warning) + $""", re.VERBOSE, + ), + "setval": "logging trap {{ trap.severity }}", + "result": { + "trap": { + "severity": "{{ severity }}", + }, + }, + }, + { + "name": "trap.state", + "getval": re.compile( + r""" + ^logging\strap + \s(?P<disable>disable) + $""", re.VERBOSE, + ), + "setval": "{{ 'logging trap disable' if trap.state =='disabled' else 'no logging trap disable' }}", + "result": { + "trap": { + "state": "{{ 'disabled' if disable is defined }}", + }, + }, + }, + { + "name": "tls_servers", + "getval": re.compile( + r""" + ^logging\stls-server\s(?P<name>\S+) + (\s+vrf\s(?P<vrf>\S+))? + (\s+trustpoint\s(?P<trustpoint>\S+))? + (\s+tls-hostname\s(?P<tls_hostname>\S+))? + (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))? + $""", re.VERBOSE, + ), + "setval": tmplt_tls_servers, + "remval": rem_tmplt_tls_servers, + "result": { + "tls_servers": { + "{{name}}": { + "name": "{{ name }}", + "trustpoint": "{{trustpoint}}", + "vrf": "{{vrf}}", + "severity": "{{severity}}", + "tls_hostname": "{{tls_hostname}}", + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ntp_global.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ntp_global.py new file mode 100644 index 00000000..497f9c2b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ntp_global.py @@ -0,0 +1,680 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Ntp_global parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def tmplt_interfaces(config_data): + commands = [] + name = config_data.get("name") + vrf = config_data.get("vrf", "") + if vrf: + base_command = "ntp interface {name} vrf {vrf}".format( + name=name, + vrf=vrf, + ) + else: + base_command = "ntp interface {name}".format(name=name) + if config_data.get("broadcast_client"): + commands.append( + "{base_command} broadcast client".format( + base_command=base_command, + ), + ) + if config_data.get("broadcast_key"): + commands.append( + "{base_command} broadcast key {broadcast_key}".format( + broadcast_key=config_data.get("broadcast_key"), + base_command=base_command, + ), + ) + if config_data.get("broadcast_destination"): + commands.append( + "{base_command} broadcast destination {broadcast_destination}".format( + broadcast_destination=config_data.get("broadcast_destination"), + base_command=base_command, + ), + ) + if config_data.get("broadcast_version"): + commands.append( + "{base_command} broadcast version {broadcast_version}".format( + broadcast_version=config_data.get("broadcast_version"), + base_command=base_command, + ), + ) + if config_data.get("multicast_destination"): + commands.append( + "{base_command} multicast destination {multicast_destination}".format( + multicast_destination=config_data.get("multicast_destination"), + base_command=base_command, + ), + ) + if config_data.get("multicast_client"): + commands.append( + "{base_command} multicast client {multicast_client}".format( + multicast_client=config_data.get("multicast_client"), + base_command=base_command, + ), + ) + if config_data.get("multicast_key"): + commands.append( + "{base_command} multicast key {multicast_key}".format( + multicast_key=config_data.get("multicast_key"), + base_command=base_command, + ), + ) + elif config_data.get("multicast_version"): + commands.append( + "{base_command} multicast version {multicast_version}".format( + multicast_version=config_data.get("multicast_version"), + base_command=base_command, + ), + ) + elif config_data.get("multicast_ttl"): + commands.append( + "{base_command} multicast ttl {multicast_ttl}".format( + multicast_ttl=config_data.get("multicast_ttl"), + base_command=base_command, + ), + ) + return commands + + +def tmplt_access_group_vrfs(config_data): + commands = [] + vrf_name = config_data.get("name") + base_command = "ntp access-group vrf {name}".format(name=vrf_name) + for ip in ["ipv4", "ipv6"]: + if config_data.get(ip, {}).get("serve"): + commands.append( + "{base_command} {ip} serve {serve}".format( + base_command=base_command, + serve=config_data.get(ip, {}).get("serve"), + ip=ip, + ), + ) + if config_data.get(ip, {}).get("serve_only"): + commands.append( + "{base_command} {ip} serve-only {serve_only}".format( + base_command=base_command, + serve_only=config_data.get(ip, {}).get("serve_only"), + ip=ip, + ), + ) + if config_data.get(ip, {}).get("query_only"): + commands.append( + "{base_command} {ip} query-only {query_only}".format( + base_command=base_command, + query_only=config_data.get(ip, {}).get("query_only"), + ip=ip, + ), + ) + if config_data.get(ip, {}).get("peer"): + commands.append( + "{base_command} {ip} peer {peer}".format( + base_command=base_command, + peer=config_data.get(ip, {}).get("peer"), + ip=ip, + ), + ) + + return commands + + +class Ntp_globalTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Ntp_globalTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "access_group.ipv4.peer", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv4\speer\s(?P<peer>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv4 peer {{access_group.ipv4.peer}}", + "result": { + "access_group": { + "ipv4": { + "peer": "{{ peer }}", + }, + }, + }, + }, + { + "name": "access_group.ipv4.serve", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv4\sserve\s(?P<serve>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv4 serve {{access_group.ipv4.serve}}", + "result": { + "access_group": { + "ipv4": { + "serve": "{{ serve }}", + }, + }, + }, + }, + { + "name": "access_group.ipv4.serve_only", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv4\sserve-only\s(?P<serve>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv4 serve-only {{access_group.ipv4.serve_only}}", + "result": { + "access_group": { + "ipv4": { + "serve_only": "{{ serve }}", + }, + }, + }, + }, + { + "name": "access_group.ipv4.query_only", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv4\squery-only\s(?P<query_only>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv4 query-only {{access_group.ipv4.query_only}}", + "result": { + "access_group": { + "ipv4": { + "query_only": "{{ query_only }}", + }, + }, + }, + }, + { + "name": "access_group.ipv6.peer", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv6\speer\s(?P<peer>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv6 peer {{access_group.ipv6.peer}}", + "result": { + "access_group": { + "ipv6": { + "peer": "{{ peer }}", + }, + }, + }, + }, + { + "name": "access_group.ipv6.serve", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv6\sserve\s(?P<serve>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv6 serve {{access_group.ipv6.serve}}", + "result": { + "access_group": { + "ipv6": { + "serve": "{{ serve }}", + }, + }, + }, + }, + { + "name": "access_group.ipv6.serve_only", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv6\sserve-only\s(?P<serve>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv6 serve-only {{access_group.ipv6.serve_only}}", + "result": { + "access_group": { + "ipv6": { + "serve_only": "{{ serve }}", + }, + }, + }, + }, + { + "name": "access_group.ipv6.query_only", + "getval": re.compile( + r""" + ^ntp\saccess-group\sipv6\squery-only\s(?P<query_only>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp access-group ipv6 query-only {{access_group.ipv6.query_only}}", + "result": { + "access_group": { + "ipv6": { + "query_only": "{{ query_only }}", + }, + }, + }, + }, + { + "name": "vrfs", + "getval": re.compile( + r""" + ^ntp\saccess-group + (\svrf\s(?P<vrf>\S+)) + (\s(?P<ipv6>ipv6))? + (\s(?P<ipv4>ipv4))? + (\speer\s(?P<peer>\S+))? + (\sserve\s(?P<serve>\S+))? + (\sserve-only\s(?P<serve_only>\S+))? + (\squery-only\s(?P<query_only>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_access_group_vrfs, + "result": { + "access_group": { + "vrfs": { + "{{vrf}}": { + "name": "{{vrf}}", + "ipv6": { + "query_only": "{{ query_only if ipv6 is defined else ''}}", + "serve_only": "{{ serve_only if ipv6 is defined else ''}}", + "serve": "{{ serve if ipv6 is defined else ''}}", + "peer": "{{ peer if ipv6 is defined else ''}}", + }, + "ipv4": { + "query_only": "{{ query_only if ipv4 is defined else ''}}", + "serve_only": "{{ serve_only if ipv4 is defined else ''}}", + "serve": "{{ serve if ipv4 is defined else ''}}", + "peer": "{{ peer if ipv4 is defined else '' }}", + }, + }, + }, + }, + }, + }, + { + "name": "authenticate", + "getval": re.compile( + r""" + ^ntp\s(?P<authenticate>authenticate) + $""", re.VERBOSE, + ), + "setval": "ntp authenticate", + "result": { + "authenticate": "{{ not not authenticate }}", + }, + }, + { + "name": "authentication_keys", + "getval": re.compile( + r""" + ^ntp\sauthentication-key\s(?P<id>\d+)\smd5\s(?P<encryption>encrypted)\s(?P<key>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp authentication-key {{ id }} md5 " + "{{ ('encrypted ') if encryption else 'clear ' }}" + "{{ key }}", + "result": { + "authentication_keys": [ + { + "id": "{{ id }}", + "key": "{{ key }}", + "encryption": "{{ not not encryption }}", + }, + ], + }, + }, + { + "name": "log_internal_sync", + "getval": re.compile( + r""" + ^ntp\s(?P<log_internal_sync>log-internal-sync) + $""", re.VERBOSE, + ), + "setval": "ntp log-internal-sync", + "result": { + "log_internal_sync": "{{ not not log_internal_sync }}", + }, + }, + { + "name": "broadcastdelay", + "getval": re.compile( + r""" + ^ntp\sbroadcastdelay\s(?P<broadcastdelay>\d+) + $""", re.VERBOSE, + ), + "setval": "ntp broadcastdelay {{ broadcastdelay }}", + "result": { + "broadcastdelay": "{{ broadcastdelay }}", + }, + }, + { + "name": "drift.aging_time", + "getval": re.compile( + r""" + ^ntp\sdrift\saging\stime\s(?P<aging_time>\d+) + $""", re.VERBOSE, + ), + "setval": "ntp drift aging time {{ drift.aging_time }}", + "result": { + "drift": { + "aging_time": "{{ aging_time }}", + }, + }, + }, + { + "name": "drift.file", + "getval": re.compile( + r""" + ^ntp\sdrift\sfile\s(?P<file>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp drift file {{ drift.file }}", + "result": { + "drift": { + "file": "{{ file }}", + }, + }, + }, + { + "name": "ipv4.dscp", + "getval": re.compile( + r""" + ^ntp + \sipv4\sdscp\s(?P<dscp>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp ipv4 dscp {{ipv4.dscp}}", + "result": { + "ipv4": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv4.precedence", + "getval": re.compile( + r""" + ^ntp + (\sipv4\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "ntp ipv4 precedence {{ipv4.precedence}}", + "result": { + "ipv4": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "ipv6.dscp", + "getval": re.compile( + r""" + ^ntp + \sipv6\sdscp\s(?P<dscp>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp ipv6 dscp {{ipv6.dscp}}", + "result": { + "ipv6": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv6.precedence", + "getval": re.compile( + r""" + ^ntp + (\sipv6\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "ntp ipv6 precedence {{ipv6.precedence}}", + "result": { + "ipv6": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "max_associations", + "getval": re.compile( + r""" + ^ntp\smax-associations\s(?P<max_associations>\d+) + $""", re.VERBOSE, + ), + "setval": "ntp max-associations {{ max_associations }}", + "result": { + "max_associations": "{{ max_associations }}", + }, + }, + { + "name": "master.stratum", + "getval": re.compile( + r""" + ^ntp\smaster\s(?P<master>\d+) + $""", re.VERBOSE, + ), + "setval": "ntp master {{ master.stratum }}", + "result": { + "master": { + "stratum": "{{ master }}", + }, + }, + }, + { + "name": "passive", + "getval": re.compile( + r""" + ^ntp\s(?P<passive>passive) + $""", re.VERBOSE, + ), + "setval": "ntp passive", + "result": { + "passive": "{{ not not passive }}", + }, + }, + { + "name": "update_calendar", + "getval": re.compile( + r""" + ^ntp\s(?P<update_calendar>update-calendar) + $""", re.VERBOSE, + ), + "setval": "ntp update-calendar", + "result": { + "update_calendar": "{{ not not update_calendar }}", + }, + }, + { + "name": "source_interface", + "getval": re.compile( + r""" + ^ntp\ssource\s(?P<source>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp source {{ source_interface }}", + "result": { + "source_interface": "{{ source }}", + }, + }, + { + "name": "source_vrfs", + "getval": re.compile( + r""" + ^ntp\ssource\svrf\s(?P<vrf>\S+)\s(?P<source>\S+) + $""", re.VERBOSE, + ), + "setval": "ntp vrf {{vrf}} source {{name}}", + "result": { + "source_vrfs": { + "{{vrf}}": { + "name": "{{ source }}", + "vrf": "{{vrf}}", + }, + }, + }, + }, + { + "name": "trusted_keys", + "getval": re.compile( + r""" + ^ntp\strusted-key\s(?P<key>\d+) + $""", re.VERBOSE, + ), + "setval": "ntp trusted-key {{ key_id }}", + "result": { + "trusted_keys": [ + { + "key_id": "{{ key }}", + }, + ], + }, + }, + { + "name": "peers", + "getval": re.compile( + r""" + ^ntp\speer + (\svrf\s(?P<vrf>\S+))? + \s(?P<peer>\S+) + (\sversion\s(?P<version>\d+))? + (\skey\s(?P<key>\d+))? + (\sminpoll\s(?P<minpoll>\d+))? + (\smaxpoll\s(?P<maxpoll>\d+))? + (\s(?P<prefer>prefer))? + (\s(?P<burst>burst))? + (\s(?P<iburst>iburst))? + (\ssource\s(?P<source>\S+))? + $""", re.VERBOSE, + ), + "setval": "ntp peer" + "{{ (' vrf ' + vrf) if vrf is defined else '' }}" + "{{ ( ' ' + peer ) if peer is defined else '' }}" + "{{ ' burst' if burst is defined else ''}}" + "{{ ' iburst' if iburst is defined else ''}}" + "{{ (' key ' + key_id|string) if key_id is defined else '' }}" + "{{ (' minpoll ' + minpoll|string) if minpoll is defined else '' }}" + "{{ (' maxpoll ' + maxpoll|string) if maxpoll is defined else '' }}" + "{{ ' prefer' if prefer is defined else ''}}" + "{{ (' version ' + version|string) if version is defined else '' }}" + "{{ (' source ' + source|string) if source is defined else '' }}", + "result": { + "peers": { + "{{peer}}_{{vrf|d()}}": { + "peer": "{{ peer }}", + "vrf": "{{ vrf }}", + "burst": "{{ not not burst }}", + "iburst": "{{ not not iburst }}", + "key_id": "{{ key }}", + "minpoll": "{{ minpoll }}", + "maxpoll": "{{ maxpoll }}", + "prefer": "{{ not not prefer }}", + "version": "{{ version }}", + "source": "{{source}}", + }, + }, + }, + }, + { + "name": "servers", + "getval": re.compile( + r""" + ^ntp\sserver + (\svrf\s(?P<vrf>\S+))? + \s(?P<server>\S+) + (\sversion\s(?P<version>\d+))? + (\skey\s(?P<key>\d+))? + (\sminpoll\s(?P<minpoll>\d+))? + (\smaxpoll\s(?P<maxpoll>\d+))? + (\s(?P<prefer>prefer))? + (\s(?P<burst>burst))? + (\s(?P<iburst>iburst))? + (\ssource\s(?P<source>\S+))? + $""", re.VERBOSE, + ), + "setval": "ntp server" + "{{ (' vrf ' + vrf) if vrf is defined else '' }}" + "{{ ( ' ' + server ) if server is defined else '' }}" + "{{ ' burst' if burst is defined else ''}}" + "{{ ' iburst' if iburst is defined else ''}}" + "{{ (' key ' + key_id|string) if key_id is defined else '' }}" + "{{ (' minpoll ' + minpoll|string) if minpoll is defined else '' }}" + "{{ (' maxpoll ' + maxpoll|string) if maxpoll is defined else '' }}" + "{{ ' prefer' if prefer is defined else ''}}" + "{{ (' version ' + version|string) if version is defined else '' }}" + "{{ (' source ' + source|string) if source is defined else '' }}", + "result": { + "servers": { + "{{server}}_{{vrf|d()}}": { + "server": "{{ server }}", + "vrf": "{{ vrf }}", + "burst": "{{ not not burst }}", + "iburst": "{{ not not iburst }}", + "key_id": "{{ key }}", + "minpoll": "{{ minpoll }}", + "maxpoll": "{{ maxpoll }}", + "prefer": "{{ not not prefer }}", + "version": "{{ version }}", + "source": "{{source}}", + }, + }, + }, + }, + { + "name": "interfaces", + "getval": re.compile( + r""" + ^ntp\sinterface\s(?P<name>\S+) + (\svrf\s(?P<vrf>\S+))? + (\smulticast\sclient\s(?P<m_client>\S+))? + (\smulticast\skey\s(?P<m_key>\S+))? + (\smulticast\sdestination\s(?P<m_dest>\S+))? + (\smulticast\sversion\s(?P<m_version>\S+))? + (\smulticast\sttl\s(?P<m_ttl>\S+))? + (\sbroadcast\sclient(?P<b_client>))? + (\sbroadcast\skey\s(?P<b_key>\S+))? + (\sbroadcast\sdestination\s(?P<b_dest>\S+))? + (\sbroadcast\sversion\s(?P<ntp_version>\d+))? + $""", re.VERBOSE, + ), + "setval": tmplt_interfaces, + "result": { + "interfaces": { + "{{name}}_{{vrf|d()}}": { + "vrf": "{{vrf}}", + "name": "{{name}}", + "broadcast_client": "{{True if b_client is defined}}", + "multicast_key": "{{m_key}}", + "multicast_destination": "{{m_dest}}", + "multicast_client": "{{m_client}}", + "multicast_version": "{{m_version}}", + "multicast_ttl": "{{m_ttl}}", + "broadcast_key": "{{b_key}}", + "broadcast_destination": "{{b_dest}}", + "broadcast_version": "{{ntp_version}}", + }, + }, + }, + }, + + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospf_interfaces.py new file mode 100644 index 00000000..a6181edd --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospf_interfaces.py @@ -0,0 +1,1416 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def get_ospf_type(afi): + return "ospf" if afi == "ipv4" else "ospfv3" + + +def get_interface_type(name): + return "GigabitEthernet" if name.startswith("GigabitEthernet") else "Loopback" + + +def _compute_command(cfg): + ospf_type = get_ospf_type(cfg["address_family"]["afi"]) + type = get_interface_type(cfg["name"]) + area = cfg["address_family"]["processes"]["area"] + pid = cfg["address_family"]["processes"]["process_id"] + cmd = "router {0} {1} area {2} interface {3} {4}".format( + ospf_type, + pid, + area["area_id"], + type, + cfg["name"].split(type)[1], + ) + return cmd + + +def _tmplt_ospf_int_delete(config_data): + ospf_type = get_ospf_type(config_data["afi"]) + type = get_interface_type(config_data["name"]) + area = config_data["area"] + command = "router {0} {1} area {2} interface {3} {4}".format( + ospf_type, + config_data["process"], + area["area_id"], + type, + config_data["name"].split(type)[1], + ) + return command + + +def _tmplt_ospf_config(config_data): + command = _compute_command(config_data) + return command + + +def _tmplt_ospf_authentication_md_config(config_data): + command = _compute_command(config_data) + auth = config_data["address_family"]["authentication"] + if auth["message_digest"].get("keychain"): + command += " authentication message-digest keychain " + auth["message_digest"]["keychain"] + return command + + +def _tmplt_ospf_authentication_md_set(config_data): + command = _compute_command(config_data) + auth = config_data["address_family"]["authentication"] + if auth.get("message_digest") and auth["message_digest"].get("keychain"): + command += " authentication message-digest" + elif auth.get("null_auth"): + command += " authentication null" + return command + + +def _tmplt_ospf_authentication_key(config_data): + command = _compute_command(config_data) + auth = config_data["address_family"]["authentication_key"] + if auth.get("password"): + command += " authentication-key " + auth["password"] + elif auth.get("encrypted"): + command += " authentication-key encrypted " + auth["encrypted"] + elif auth.get("clear"): + command += " authentication-key clear " + auth["clear"] + return command + + +def _tmplt_ospf_int_bfd_min_int(config_data): + command = _compute_command(config_data) + bfd = config_data["address_family"]["bfd"] + if bfd.get("minimum_interval"): + command += " bfd minimum-interval " + str(bfd["minimum_interval"]) + return command + + +def _tmplt_ospf_int_bfd_mult(config_data): + command = _compute_command(config_data) + bfd = config_data["address_family"]["bfd"] + if bfd.get("multiplier"): + command += " bfd multiplier " + str(bfd["multiplier"]) + return command + + +def _tmplt_ospf_int_bfd_fd(config_data): + command = _compute_command(config_data) + bfd = config_data["address_family"]["bfd"] + if bfd.get("fast_detect") and bfd["fast_detect"].get("set"): + command += " bfd fast-detect" + elif bfd.get("fast_detect") and bfd["fast_detect"].get("disable"): + command += " bfd fast-detect disable" + elif bfd.get("fast_detect") and bfd["fast_detect"].get("strict_mode"): + command += " bfd fast-detect strict-mode" + return command + + +def _tmplt_ospf_cost_config(config_data): + command = _compute_command(config_data) + command += " cost " + str(config_data["address_family"]["cost"]) + return command + + +def _tmplt_ospf_cost_fallback_config(config_data): + command = _compute_command(config_data) + fallback = config_data["address_family"]["cost_fallback"] + command += ( + " cost-fallback " + str(fallback["cost"]) + " threshold " + str(fallback["threshold"]) + ) + return command + + +def _tmplt_ospf_dead_int_config(config_data): + command = _compute_command(config_data) + command += " dead-interval " + str( + config_data["address_family"]["dead_interval"], + ) + return command + + +def _tmplt_ospf_demand_config(config_data): + command = _compute_command(config_data) + if config_data["address_family"]["demand_circuit"]: + command += " demand-circuit enable" + else: + command += " demand-circuit disable" + return command + + +class Ospf_interfacesTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Ospf_interfacesTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "name", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + $''', + re.VERBOSE, + ), + "remval": _tmplt_ospf_int_delete, + "setval": _tmplt_ospf_config, + "compval": "name", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + }, + }, + }, + "shared": True, + }, + { + "name": "authentication.message_digest", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sauthentication(?P<authentication>) + \s(?P<opt>message-digest) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_md_set, + "compval": "address_family.authentication.message_digest", + "result": { + "{{ name }}": { + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "authentication": { + "set": "{{ True if authentication is defined and opt is undefined }}", + "message_digest": { + "set": "{{ True if opt == 'message-digest' else None }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "authentication.message_digest.keychain", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sauthentication(?P<authentication>) + \s(?P<message_digest>message-digest) + \skeychain\s(?P<keychain>\S+)$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_md_config, + "compval": "address_family.authentication.message_digest.keychain", + "result": { + "{{ name }}": { + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "authentication": { + "message_digest": { + "keychain": "{{ keychain }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "authentication.null_auth", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sauthentication(?P<authentication>) + \s(?P<opt>null) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_md_set, + "compval": "address_family.authentication.null_auth", + "result": { + "{{ name }}": { + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "authentication": { + "set": "{{ True if authentication is defined and opt is undefined }}", + "null_auth": "{{ True if opt == 'null' else None }}", + }, + }, + }, + }, + }, + }, + { + "name": "authentication_key", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sauthentication-key + (\sencrypted\s(?P<encrypted>\S+))? + (\s(?P<key>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_key, + "compval": "address_family.authentication_key", + "result": { + "{{ name }}": { + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "authentication_key": { + "encrypted": "{{ encrypted }}", + }, + }, + }, + }, + }, + }, + { + "name": "bfd.minimum_interval", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sbfd(?P<bfd>) + \sminimum-interval\s(?P<minimum_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_int_bfd_min_int, + "compval": "address_family.bfd.minimum_interval", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + + }, + }, + "bfd": { + "minimum_interval": "{{ minimum_interval|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "bfd.multiplier", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sbfd(?P<bfd>) + \smultiplier\s(?P<multiplier>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_int_bfd_mult, + "compval": "address_family.bfd.multiplier", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + + }, + }, + "bfd": { + "multiplier": "{{ multiplier|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "bfd.fast_detect.set", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sbfd(?P<bfd>) + \sfast-detect(?P<fast_detect>) + (\s(?P<opt>(disable|strict-mode)))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_int_bfd_fd, + "compval": "address_family.bfd.fast_detect.set", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + + }, + }, + "bfd": { + "fast_detect": { + "set": "{{ True if opt != 'disable' and opt != 'strict-mode' and fast_detect is defined else None }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd.fast_detect.disable", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sbfd(?P<bfd>) + \sfast-detect(?P<fast_detect>) + (\s(?P<opt>(disable|strict-mode)))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_int_bfd_fd, + "compval": "address_family.bfd.fast_detect.disable", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + + }, + }, + "bfd": { + "fast_detect": { + "disable": "{{ True if opt == 'disable' else None }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "bfd.fast_detect.strict_mode", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sbfd(?P<bfd>) + \sfast-detect(?P<fast_detect>) + \s(?P<opt>strict-mode) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_int_bfd_fd, + "compval": "address_family.bfd.fast_detect.strict_mode", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "bfd": { + "fast_detect": { + "strict_mode": "{{ True if opt == 'strict-mode' else None }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "cost", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \scost\s(?P<cost>\S+)$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_cost_config, + "compval": "address_family.cost", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "cost": "{{ cost }}", + }, + }, + }, + }, + }, + { + "name": "cost_fallback", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \scost-fallback\s(?P<cost>\S+) + \sthreshold\s(?P<threshold>\S+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_cost_fallback_config, + "compval": "address_family.cost_fallback", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "cost_fallback": { + "cost": "{{ cost }}", + "threshold": "{{ threshold }}", + }, + }, + }, + }, + }, + }, + { + "name": "dead_interval", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sdead-interval\s(?P<dead_interval>\S+) + $''', + re.VERBOSE, + ), + "setval": _tmplt_ospf_dead_int_config, + "compval": "address_family.dead_interval", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "dead_interval": "{{ dead_interval }}", + }, + }, + }, + }, + }, + { + "name": "demand_circuit", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sdemand-circuit\s(?P<demand_circuit>\S+) + $''', + re.VERBOSE, + ), + "setval": _tmplt_ospf_demand_config, + "compval": "address_family.demand_circuit", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "demand_circuit": "{{ True if demand_circuit == 'enable' else False if demand_circuit == 'disable' else None }}", + }, + }, + }, + }, + }, + { + "name": "flood_reduction", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sflood-reduction\s(?P<flood_reduction>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "flood-reduction {{ 'enable' if flood_reduction == True else 'disable' }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "flood_reduction": "{{ True if flood_reduction == 'enable' else False if flood_reduction == 'disable' else None }}", + }, + }, + }, + }, + }, + { + "name": "hello_interval", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \shello-interval\s(?P<dead_interval>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "hello-interval {{ hello_interval }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "hello_interval": "{{ hello_interval }}", + }, + }, + }, + }, + }, + { + "name": "link_down.set", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<link_down>link-down) + (\s(?P<disable>disable))? + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "link-down", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "link_down": { + "set": "{{ True if link_down is defined and disable is undefined else None}}", + }, + }, + }, + }, + }, + }, + { + "name": "link_down.disable", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<link_down>link-down) + \s(?P<disable>disable) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "link-down disable", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "link_down": { + "disable": "{{ True if disable is defined else None }}", + }, + }, + }, + }, + }, + }, + { + "name": "message_digest_key", + "getval": re.compile( + r""" + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \smessage-digest-key + \s(?P<id>\d+) + \smd5 + \s(?P<encryption>\d) + \s(?P<key>\S+)$""", + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface " + "{{ type }} {{ name }} #message-digest-key {{ message_digest_key.id }} " + "md5 encrypted {{ message_digest_key.encrypted}}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "message_digest_key": { + "id": "{{ id }}", + "encrypted": "{{ encryption }}", + }, + }, + }, + }, + }, + }, + { + "name": "mpls.set_ldp", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<mpls>mpls) + \s(?P<ldp>set_ldp) + (\s(?P<sync>sync))? + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "mpls ldp", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "mpls": { + "set_ldp": "{{ True if set_ldp is defined and sync is undefined else None}}", + }, + }, + }, + }, + }, + }, + { + "name": "mpls.ldp_sync", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<mpls>mpls) + \s(?P<ldp>ldp) + \s(?P<sync>sync) + (\s(?P<disable>disable))? + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "mpls ldp sync", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "mpls": { + "ldp_sync": "{{ True if sync is defined and disable is undefined else None}}", + }, + }, + }, + }, + }, + }, + { + "name": "mpls.ldp_sync_disable", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<mpls>mpls) + \s(?P<ldp>ldp) + \s(?P<sync>sync) + \s(?P<disable>disable) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "mpls ldp sync disable", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "mpls": { + "ldp_sync": "{{ False if disable is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "mtu_ignore", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \smtu-ignore\s(?P<mtu_ignore>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "mtu_ignore {{ 'enable' if mtu_ignore == 'True' else 'disable' if mtu_ignore == 'False' }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "mtu_ignore": "{{ True if mtu_ignore == 'enable' else False if mtu_ignore == 'disable' else None }}", + }, + }, + }, + }, + }, + { + "name": "network", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \snetwork\s(?P<network>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "network {{ network }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "network": "{{ network }}", + }, + }, + }, + }, + }, + { + "name": "packet_size", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \spacket-size\s(?P<packet_size>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "packet-size {{ packet_size }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "packet_size": "{{ packet_size }}", + }, + }, + }, + }, + }, + { + "name": "passive", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \spassive\s(?P<passive>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "passive {{ 'enable' if passive == 'True' else 'disable' if passive == 'False' }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "passive": "{{ True if passive == 'enable' else False if passive == 'disable' else None }}", + }, + }, + }, + }, + }, + { + "name": "prefix_suppression.disable", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sprefix-suppression\s(?P<prefix_suppression>\S+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "prefix-suppression {{ prefix_suppression }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "prefix_suppression": { + "disable": "{{ True if prefix_suppression == 'disable' else None }}", + }, + }, + }, + }, + }, + }, + { + "name": "prefix_suppression.secondary_address", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<prefix_suppression>prefix-suppression) + \s(?P<secondary_address>secondary-address) + (\s(?P<disable>disable))? + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "prefix-suppression secondary-address {{ disable if secondary_address is False }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "prefix_suppression": { + "secondary_address": "{{ True if secondary_address is defined and " + "disable is undefined else False if disable is defined else None }}", + }, + }, + }, + }, + }, + }, + { + "name": "priority", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \spriority\s(?P<priority>\d+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "priority {{ priority }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "priority": "{{ priority|int }}", + }, + }, + }, + }, + }, + { + "name": "retransmit_interval", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \sretransmit-interval\s(?P<retransmit_interval>\d+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "retransmit-interval {{ retransmit_interval }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "retransmit_interval": "{{ retransmit_interval|int }}", + }, + }, + }, + }, + }, + { + "name": "security.ttl_hops", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<security>security) + \s(?P<ttl>ttl) + \shops\s(?P<hops>\d+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "security ttl hops {{ hops }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "security_ttl": { + "hops": "{{ hops|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "security.ttl", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \s(?P<security>security) + \s(?P<ttl>ttl) + (\s(?P<hops>hops))? + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "security ttl", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "security_ttl": { + "set": "{{ True if ttl is defined and hops is undefined }}", + }, + }, + }, + }, + }, + }, + { + "name": "transmit_delay", + "getval": re.compile( + r''' + ^router + \s(?P<ospf_type>ospf|ospfv3) + \s(?P<process_id>\S+) + \sarea\s(?P<area_id>\S+) + \sinterface\s(?P<name>\S+) + \stransmit-delay\s(?P<transmit_delay>\d+) + $''', + re.VERBOSE, + ), + "setval": "router {{ ospf_type }} {{ process_id }} area {{ area_id }} interface {{ type }} {{ name }} " + "transmit-delay {{ transmit_delay }}", + "result": { + "{{ name }}": { + "name": "{{ name }}", + "type": "{{ 'gigabitethernet' if 'GigabitEthernet' in name else 'loopback' if 'Loopback' in name }}", + "address_family": { + "{{ ospf_type }}": { + "afi": "{{ 'ipv4' if ospf_type == 'ospf' else 'ipv6' }}", + "processes": { + "{{ process_id }}": { + "process_id": "{{ process_id }}", + "area": { + "area_id": "{{ area_id }}", + }, + }, + }, + "transmit_delay": "{{ transmit_delay|int }}", + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv2.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv2.py new file mode 100644 index 00000000..e5a54a64 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv2.py @@ -0,0 +1,2856 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def _tmplt_ospf_default_information(config_data): + if "default_information_originate" in config_data: + command = "default-information originate" + if "always" in config_data["default_information_originate"]: + command += " always" + if "metric" in config_data["default_information_originate"]: + command += " metric {metric}".format(**config_data["default_information_originate"]) + if "metric_type" in config_data["default_information_originate"]: + command += " metric-type {metric_type}".format( + **config_data["default_information_originate"] + ) + if "route_policy" in config_data["default_information_originate"]: + command += " route-policy {route_policy}".format( + **config_data["default_information_originate"] + ) + return command + + +def _tmplt_ospf_auto_cost(config_data): + if "auto_cost" in config_data: + command = "auto-cost" + if "disable" in config_data["auto_cost"]: + command += " disable" + if "reference_bandwidth" in config_data["auto_cost"]: + command += " reference-bandwidth {reference_bandwidth}".format( + **config_data["auto_cost"] + ) + return command + + +def _tmplt_ospf_bfd(config_data): + if "bfd" in config_data: + command = "bfd" + if "minimum_interval" in config_data["bfd"]: + command += " minimum-interval {minimum_interval}".format(**config_data["bfd"]) + + if "multiplier" in config_data["bfd"]: + command += " multiplier {multiplier}".format(**config_data["bfd"]) + + return command + + +def _tmplt_ospf_security(config_data): + if "security_ttl" in config_data: + command = "security_ttl" + if "set" in config_data["security_ttl"]: + command += " ttl" + elif config_data["security_ttl"].get("hops"): + command += " ttl hops {0}".format( + config_data["security_ttl"].get("hops"), + ) + return command + + +def _tmplt_ospf_log_adjacency(config_data): + if "log_adjacency_changes" in config_data: + command = "log adjacency" + if "set" in config_data["log_adjacency_changes"]: + command += " changes" + elif config_data["log_adjacency_changes"].get("disable"): + command += " disable" + elif config_data["log_adjacency_changes"].get("details"): + command += " details" + return command + + +def _tmplt_ospf_log_max_lsa(config_data): + if "max_lsa" in config_data: + command = "max-lsa" + if "threshold" in config_data["max_lsa"]: + command += " {0}".format(config_data["max_lsa"].get("threshold")) + if "warning_only" in config_data["max_lsa"]: + command += " warning-only {0}".format( + config_data["max_lsa"].get("warning_only"), + ) + if "ignore_time" in config_data["max_lsa"]: + command += " ignore-time {0}".format( + config_data["max_lsa"].get("ignore_time"), + ) + if "ignore_count" in config_data["max_lsa"]: + command += " ignore-count {0}".format( + config_data["max_lsa"].get("ignore_count"), + ) + if "reset_time" in config_data["max_lsa"]: + command += " reset-time {0}".format( + config_data["max_lsa"].get("reset_time"), + ) + return command + + +def _tmplt_ospf_max_metric(config_data): + if "max_metric" in config_data: + command = "max-metric" + if "router_lsa" in config_data["max_metric"]: + command += " router-lsa" + if "external_lsa" in config_data["max_metric"]: + command += " external-lsa {external_lsa}".format(**config_data["max_metric"]) + if "include_stub" in config_data["max_metric"]: + command += " include-stub" + if "on_startup" in config_data["max_metric"]: + if "time" in config_data["max_metric"]["on_startup"]: + command += " on-startup {time}".format(**config_data["max_metric"]["on_startup"]) + elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]: + command += " on-startup wait-for-bgp" + if "summary_lsa" in config_data["max_metric"]: + command += " summary-lsa {summary_lsa}".format(**config_data["max_metric"]) + return command + + +def _tmplt_ospf_distance_admin(config_data): + if "admin_distance" in config_data: + command = "distance" + if config_data["admin_distance"].get("value"): + command += " {0}".format( + config_data["admin_distance"].get("value"), + ) + if config_data["admin_distance"].get("source"): + command += " {0}".format( + config_data["admin_distance"].get("source"), + ) + if config_data["admin_distance"].get("wildcard"): + command += " {0}".format( + config_data["admin_distance"].get("wildcard"), + ) + if config_data["admin_distance"].get("access_list"): + command += " {0}".format( + config_data["admin_distance"].get("access_list"), + ) + return command + + +def _tmplt_ospf_distance_ospf(config_data): + if "ospf_distance" in config_data: + command = "distance ospf" + if config_data["ospf_distance"].get("external"): + command += " external {0}".format( + config_data["ospf_distance"].get("external"), + ) + if config_data["ospf_distance"].get("inter_area"): + command += " inter-area {0}".format( + config_data["ospf_distance"].get("inter_area"), + ) + if config_data["ospf_distance"].get("intra_area"): + command += " intra-area {0}".format( + config_data["ospf_distance"].get("intra_area"), + ) + return command + + +def _tmplt_ospf_nsr(config_data): + if "nsr" in config_data: + command = "nsr" + if "set" in config_data["nsr"]: + command += " nsr" + elif config_data["nsr"].get("disable"): + command += " nsr {0}".format("disable") + return command + + +def _tmplt_ospf_protocol(config_data): + if "protocol_shutdown" in config_data: + command = "protocol" + if "set" in config_data["protocol_shutdown"]: + command += " shutdown" + elif config_data["shutdown"].get("host_mode"): + command += " shutdown host-mode" + elif config_data["shutdown"].get("on_reload"): + command += " shutdown on-reload" + return command + + +def _tmplt_microloop_avoidance(config_data): + if "microloop_avoidance" in config_data: + command = "microloop avoidance" + if "protected" in config_data["microloop_avoidance"]: + command += " protected" + if "segment_routing" in config_data["microloop_avoidance"]: + command += " segment_routing" + if "rib_update_delay" in config_data["microloop_avoidance"]: + command += " rin-update-delay {0}".config_data["microloop_avoidance"].get( + "rib_update_delay", + ) + return command + + +def _tmplt_ospf_bfd_fast_detect(config_data): + if "bfd" in config_data: + command = "bfd" + if "fast_detect" in config_data["bfd"]: + fast_detect = config_data["bfd"].get("fast_detect") + command += " fast-detect" + if "strict_mode" in fast_detect: + command += " strict-mode" + return command + + +def _tmplt_ospf_mpls_traffic_eng(config_data): + if "traffic_eng" in config_data: + command = "mpls traffic-eng" + if "igp_intact" in config_data["traffic_eng"]: + command += " igp-intact" + if "ldp_sync_update" in config_data["traffic_eng"]: + command += " ldp_sync_update" + if "multicast_intact" in config_data["traffic_eng"]: + command += " multicast_intact" + if "auto_route_exclude" in config_data["traffic_eng"]: + policy = config_data["traffic_eng"].get("autoroute_exclude") + command += " autoroute-exlude route-policy {0}".format( + policy.get("route_policy"), + ) + return command + + +def _tmplt_ospf_authentication_md(config_data): + command = [] + if "authentication" in config_data: + if config_data["authentication"].get("message_digest"): + command = "authentication message-digest" + md = config_data["authentication"].get("message_digest") + if md.get("keychain"): + command += " keychain " + md.get("keychain") + return command + + +def _tmplt_ospf_authentication(config_data): + command = [] + if "authentication" in config_data: + if config_data["authentication"].get("keychain"): + command = "authentication keychain " + config_data["authentication"].get("keychain") + elif config_data["authentication"].get("no_auth"): + command = "authentication null" + return command + + +def _tmplt_ospf_adjacency_stagger(config_data): + if "adjacency_stagger" in config_data: + command = "adjacency stagger".format(**config_data) + if config_data["adjacency_stagger"].get("min_adjacency") and config_data[ + "adjacency_stagger" + ].get("min_adjacency"): + command += " {0} {1}".format( + config_data["adjacency_stagger"].get("min_adjacency"), + config_data["adjacency_stagger"].get("max_adjacency"), + ) + elif config_data["adjacency_stagger"].get("disable"): + command += " disable" + return command + + +def _tmplt_ospf_adjacency_distribute_bgp_state(config_data): + if "distribute_link_list" in config_data: + command = "distribute link-state" + if config_data["distribute_link_list"].get("instance_id"): + command += " instance-id {0}".format( + config_data["distribute_link_list"].get("instance_id"), + ) + elif config_data["distribute_link_list"].get("throttle"): + command += " throttle {0}".format( + config_data["distribute_link_list"].get("throttle"), + ) + return command + elif "distribute_bgp_ls" in config_data: + command = "distribute bgp-ls" + if config_data["distribute_bgp_ls"].get("instance_id"): + command += " instance-id {0}".format( + config_data["distribute_bgp_ls"].get("instance_id"), + ) + elif config_data["distribute_bgp_ls"].get("throttle"): + command += " throttle {0}".format( + config_data["distribute_bgp_ls"].get("throttle"), + ) + return command + + +def _tmplt_ospf_capability_opaque(config_data): + if "capability" in config_data: + if "opaque" in config_data["capability"]: + command = "capability opaque" + opaque = config_data["capability"].get("opaque") + if "disable" in opaque: + command += "capability opaque disable" + return command + + +def _tmplt_ospf_authentication_key(config_data): + if "authentication_key" in config_data: + command = "authentication-key".format(**config_data) + if config_data["authentication_key"].get("password"): + command += " {0}".format( + config_data["authentication_key"].get("password"), + ) + return command + + +def _tmplt_ospf_area_authentication(config_data): + if "authentication" in config_data: + command = "area {area_id} authentication".format(**config_data) + if config_data["authentication"].get("keychain"): + command += " keychain " + config_data["authentication"].get( + "keychain", + ) + elif config_data["authentication"].get("no_auth"): + command += " null" + return command + + +def _tmplt_ospf_area_authentication_md(config_data): + if "authentication" in config_data: + command = "area {area_id} authentication".format(**config_data) + if "message_digest" in config_data["authentication"]: + command = "authentication message-digest" + md = config_data["authentication"].get("message_digest") + if md.get("keychain"): + command += " keychain " + md.get("keychain") + return command + + +def _tmplt_ospf_area_authentication_key(config_data): + if "authentication_key" in config_data: + command = "area {area_id} authentication-key".format(**config_data) + if config_data["authentication_key"].get("password"): + command += " {0}".format( + config_data["authentication_key"].get("password"), + ) + return command + + +def _tmplt_ospf_area_mpls_ldp(config_data): + commands = [] + if "mpls" in config_data: + command = "area {area_id} mpls".format(**config_data) + if config_data["mpls"].get("ldp"): + ldp = config_data["mpls"].get("ldp") + if "auto_config" in ldp: + command += " auto-config" + commands.append(command) + if "sync" in ldp: + command += " sync" + commands.append(command) + if "sync_igp_shortcuts" in ldp: + command += " sync-igp-shortcuts" + commands.append(command) + return commands + + +def _tmplt_ospf_area_bfd(config_data): + if "bfd" in config_data: + command = "area {area_id} bfd".format(**config_data) + if "minimum_interval" in config_data["bfd"]: + command += " minimum-interval {minimum_interval}".format(**config_data["bfd"]) + + if "multiplier" in config_data["bfd"]: + command += " multiplier {multiplier}".format(**config_data["bfd"]) + + return command + + +def _tmplt_ospf_area_bfd_fast_detect(config_data): + if "bfd" in config_data: + command = "area {area_id} bfd".format(**config_data) + if "fast_detect" in config_data["bfd"]: + fast_detect = config_data["bfd"].get("fast_detect") + command += " fast-detect" + if "strict_mode" in fast_detect: + command += " strict-mode" + return command + + +def _tmplt_ospf_mpls_ldp(config_data): + commands = [] + if "mpls" in config_data: + command = "mpls".format(**config_data) + if config_data["mpls"].get("ldp"): + ldp = config_data["mpls"].get("ldp") + if "auto_config" in ldp: + command += " auto-config" + commands.append(command) + if "sync" in ldp: + command += " sync" + commands.append(command) + if "sync_igp_shortcuts" in ldp: + command += " sync-igp-shortcuts" + commands.append(command) + return commands + + +def _tmplt_ospf_area_nssa(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if config_data["nssa"].get("no_redistribution"): + command += " no-redistribution" + if config_data["nssa"].get("no_summary"): + command += " no-summary" + return command + + +def _tmplt_ospf_area_nssa_def_info_origin(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if "default_information_originate" in config_data["nssa"]: + command += " default-information-originate" + def_info_origin = config_data["nssa"].get( + "default_information_originate", + ) + if "metric" in def_info_origin: + command += " metric {metric}".format( + **config_data["nssa"]["default_information_originate"] + ) + if "metric_type" in def_info_origin: + command += " metric-type {metric_type}".format( + **config_data["nssa"]["default_information_originate"] + ) + return command + + +def _tmplt_ospf_area_nssa_translate(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if config_data["nssa"].get("translate"): + command += " translate" + translate = config_data["nssa"].get("translate") + if "type7" in translate: + command += " type7" + if translate["type7"].get("always"): + command += " always" + return command + + +def _tmplt_ospf_area_vlink_authentication(config_data): + if "authentication" in config_data: + command = "area {area_id} virtual-link {id} authentication".format(**config_data) + if config_data["authentication"].get("keychain"): + command += " keychain " + config_data["authentication"].get( + "keychain", + ) + elif config_data["authentication"].get("no_auth"): + command += " null" + return command + + +def _tmplt_ospf_area_vlink_authentication_md(config_data): + if "authentication" in config_data: + command = "area {area_id} virtual-link {id} authentication".format(**config_data) + if config_data["authentication"].get("message_digest"): + command = "authentication message-digest" + md = config_data["authentication"].get("message_digest") + if md.get("keychain"): + command += " keychain " + md.get("keychain") + return command + + +def _tmplt_ospf_area_vlink_authentication_key(config_data): + if "authentication_key" in config_data: + command = "area {area_id} virtual-link {id} authentication-key".format(**config_data) + if config_data["authentication_key"].get("password"): + command += " {0}".format( + config_data["authentication_key"].get("password"), + ) + return command + + +def _tmplt_ospf_area_stub(config_data): + if "stub" in config_data: + command = "area {area_id} stub".format(**config_data) + if config_data["stub"].get("no_summary"): + command += " no-summary" + return command + + +def _tmplt_ospf_area_ranges(config_data): + if "ranges" in config_data: + commands = [] + for k, v in iteritems(config_data["ranges"]): + cmd = "area {area_id} range".format(**config_data) + temp_cmd = " {address}".format(**v) + if "advertise" in v: + temp_cmd += " advertise" + elif "not_advertise" in v: + temp_cmd += " not-advertise" + cmd += temp_cmd + commands.append(cmd) + return commands + + +def _tmplt_prefix_suppression(config_data): + if "prefix_suppression" in config_data: + if "set" in config_data["prefix_suppression"]: + command = "prefix-suppression" + if "secondary_address" in config_data["prefix_suppression"]: + command = "prefix-suppression secondary-address" + return command + + +def _tmplt_protocol_shutdown(config_data): + if "protocol_shutdown" in config_data: + if "set" in config_data["protocol_shutdown"]: + command = "protocol-shutdown" + if "host_mode" in config_data["protocol_shutdown"]: + command = "protocol-shutdown host-mode" + if "on_reload" in config_data["protocol_shutdown"]: + command = "protocol-shutdown on-reload" + return command + + +def _tmplt_timers_lsa(config_data): + if "timers" in config_data: + command = "timers lsa" + if "group_pacing" in config_data["timers"]["lsa"]: + command += " group-pacing {group_pacing}".format(**config_data["timers"]["lsa"]) + if "min_arrival" in config_data["timers"]["lsa"]: + command += " min-arrival {min_arrival}".format(**config_data["timers"]["lsa"]) + if "refresh" in config_data["timers"]["lsa"]: + command += " refresh {refresh}".format(**config_data["timers"]["lsa"]) + return command + + +def _tmplt_timers_graceful_shutdown(config_data): + if "timers" in config_data: + command = "timers graceful-shutdown" + if "initial_delay" in config_data["timers"]["graceful-shutdown"]: + command += " initial delay {initial_delay}".format( + **config_data["timers"]["graceful-shutdown"] + ) + if "retain_routes" in config_data["timers"]["graceful-shutdown"]: + command += " retain routes {retain_routes}".format( + **config_data["timers"]["graceful-shutdown"] + ) + return command + + +class Ospfv2Template(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Ospfv2Template, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "pid", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + $""", + re.VERBOSE, + ), + "setval": "router ospf {{ process_id }}", + "result": { + "processes": {"{{ pid }}": {"process_id": "{{ pid }}"}}, + }, + "shared": True, + }, + { + "name": "cost", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \scost(?P<cost>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "cost {{ cost }}", + "result": { + "processes": { + "{{ pid }}": { + "cost": "{{ cost|int }}", + }, + }, + }, + }, + { + "name": "default_metric", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdefault-metric(?P<default_metric>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "default-metric {{ default_metric }}", + "result": { + "processes": { + "{{ pid }}": { + "default_metric": "{{ default_metric|int }}", + }, + }, + }, + }, + { + "name": "packet_size", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \spacket-size(?P<packet_size>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "packet-size {{ packet_size }}", + "result": { + "processes": { + "{{ pid }}": { + "packet_size": "{{ packet_size|int }}", + }, + }, + }, + }, + { + "name": "dead_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdead-interval(?P<dead_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "dead-interval {{ dead_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "dead_interval": "{{ dead_interval|int }}", + }, + }, + }, + }, + { + "name": "hello_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \shello-interval(?P<hello_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "hello-interval {{ hello_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "hello_interval": "{{ hello_interval|int }}", + }, + }, + }, + }, + { + "name": "priority", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \spriority(?P<priority>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "priority {{ priority }}", + "result": { + "processes": { + "{{ pid }}": { + "priority": "{{ priority|int }}", + }, + }, + }, + }, + { + "name": "weight", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sweight(?P<weight>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "weight {{ weight }}", + "result": { + "processes": { + "{{ pid }}": { + "weight": "{{ weight|int }}", + }, + }, + }, + }, + { + "name": "retransmit_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sretransmit-interval(?P<retransmit_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "retransmit-interval {{ retransmit_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "retransmit_interval": "{{ retransmit_interval|int }}", + }, + }, + }, + }, + { + "name": "transmit_delay", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stransmit-delay(?P<transmit_delay>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "transmit-delay {{ transmit_delay }}", + "result": { + "processes": { + "{{ pid }}": { + "transmit_delay": "{{ transmit_delay|int }}", + }, + }, + }, + }, + { + "name": "passive", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \spassive\s(?P<passive>\S+) + $""", + re.VERBOSE, + ), + + "setval": "passive {{ passive }}", + "result": { + "processes": { + "{{ pid }}": { + "passive": "{{ passive }}", + }, + }, + }, + }, + { + "name": "process.database_filter", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdatabase-filter + \sall + \sout\s(?P<database_filter>\s\S+) + $""", + re.VERBOSE, + ), + + "setval": "process.database_filter", + "result": { + "processes": { + "{{ pid }}": { + "database_filter": "{{ database_filter }}", + }, + }, + }, + }, + { + "name": "demand_circuit", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdemand-circuit\s(?P<demand_circuit>\S+) + $""", + re.VERBOSE, + ), + + "setval": "demand-circuit {{ demand_circuit }}", + "result": { + "processes": { + "{{ pid }}": { + "demand_circuit": "{{ demand_circuit }}", + }, + }, + }, + }, + { + "name": "external_out", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sexternal-out\s(?P<external_out>\S+) + $""", + re.VERBOSE, + ), + + "setval": "external-out {{ external_out }}", + "result": { + "processes": { + "{{ pid }}": { + "external_out": "{{ external_out }}", + }, + }, + }, + }, + { + "name": "router_id", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \srouter-id\s(?P<router_id>\S+) + $""", + re.VERBOSE, + ), + + "setval": "router-id {{ router_id }}", + "result": { + "processes": { + "{{ pid }}": { + "router_id": "{{ router_id }}", + }, + }, + }, + }, + { + "name": "summary_in", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \ssummary-in\s(?P<summary_in>\S+) + $""", + re.VERBOSE, + ), + + "setval": "summary-in {{ summary_in }}", + "result": { + "processes": { + "{{ pid }}": { + "summary_in": "{{ summary_in }}", + }, + }, + }, + }, + + { + "name": "mtu_ignore", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \smtu-ignore\s(?P<mtu_ignore>\S+) + $""", + re.VERBOSE, + ), + + "setval": "mtu-ignore {{ mtu_ignore }}", + "result": { + "processes": { + "{{ pid }}": { + "mtu_ignore": "{{ mtu_ignore }}", + }, + }, + }, + }, + { + "name": "flood_reduction", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sflood-reduction\s(?P<flood_reduction>\S+) + $""", + re.VERBOSE, + ), + + "setval": "flood-reduction {{ flood_reduction }}", + "result": { + "processes": { + "{{ pid }}": { + "flood_reduction": "{{ flood_reduction }}", + }, + }, + }, + }, + { + "name": "loopback_stub_network", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sloopback(?P<loopback>) + \sstub-network\s(?P<stub_network>\S+) + $""", + re.VERBOSE, + ), + + "setval": "loopback stub-network {{ stub_network }}", + "result": { + "processes": { + "{{ pid }}": { + "loopback_stub_network": "{{ loopback_stub_network }}", + }, + }, + }, + }, + { + "name": "address_family_unicast", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \saddress-family(?P<address_family>) + \sipv4(?P<ipv4>) + \sunicast(?P<unicast>) + $""", + re.VERBOSE, + ), + + "setval": "address_family_unicast", + "result": { + "processes": { + "{{ pid }}": { + "address_family_unicast": "{{ True if unicast is defined }}", + }, + }, + }, + }, + { + "name": "default_weight", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sapply-weight(?P<apply_weight>) + \sdefault-weight(?P<default_weight>\s\d+) + $""", + re.VERBOSE, + ), + "setval": "apply-weight default-weight {{ default_weight }}", + "result": { + "processes": { + "{{ pid }}": { + "apply_weight": { + "default_weight": "{{ default_weight|int }}", + }, + }, + }, + }, + }, + { + "name": "bandwidth", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sapply-weight(?P<apply_weight>) + \sbandwidth(?P<bandwidth>\s\d+)? + $""", + re.VERBOSE, + ), + "setval": "apply-weight bandwidth {{ bandwidth }}", + "result": { + "processes": { + "{{ pid }}": { + "apply_weight": { + "bandwidth": "{{ bandwidth|int }}", + }, + }, + }, + }, + }, + { + "name": "adjacency_stagger", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sadjacency(?P<adjacency>) + \sstagger(?P<stagger>) + (\s(?P<min_adjacency>\d+))? + (\s(?P<max_adjacency>\d+))? + (\sdisable(?P<disable>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_adjacency_stagger, + "result": { + "processes": { + "{{ pid }}": { + "adjacency_stagger": { + "min_adjacency": "{{ min_adjacency|int }}", + "max_adjacency": "{{ max_adjacency }}", + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + { + "name": "authentication", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sauthentication(?P<auth>) + (\skeychain\s(?P<keychain>\S+)*)? + (\snull(?P<no_auth>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication, + "result": { + "processes": { + "{{ pid }}": { + "authentication": { + "no_auth": "{{ True if no_auth is defined }}", + "keychain": "{{ keychain }}", + }, + }, + }, + }, + }, + { + "name": "authentication.message_digest", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sauthentication(?P<auth>) + \smessage-digest(?P<md>) + \skeychain\s(?P<md_key>\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_md, + "result": { + "processes": { + "{{ pid }}": { + "authentication": { + "message_digest": { + "keychain": "{{ md_key }}", + "set": "{{ True if md is defined and md_key is undefined }}", + }, + }, + }, + }, + }, + }, + { + "name": "default_information_originate", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdefault-information(?P<default_information>) + (\soriginate(?P<originate>))? + (\salways(?P<always>))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + (\sroute_policy\s(?P<route_policy>)\S+)? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_default_information, + "result": { + "processes": { + "{{ pid }}": { + "default_information_originate": { + "always": "{{ True if always is defined }}", + "metric": "{{ metric|int }}", + "metric_type": "{{ metric_type|int }}", + "route_policy": "{{ route_policy }}", + "set": "{{ True if default_information is defined and always is undefined and metric " + "is undefined and metric_type is undefined and route_policy is undefined }}", + }, + }, + }, + }, + }, + { + "name": "auto_cost", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sauto-cost(?P<auto_cost>) + (\sreference-bandwidth\s(?P<reference_bandwidth>\d+))? + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_auto_cost, + "result": { + "processes": { + "{{ pid }}": { + "auto_cost": { + "disable": "{{ True if disable is defined }}", + "reference_bandwidth": "{{ reference_bandwidth|int }}", + }, + }, + }, + }, + }, + { + "name": "bfd", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sbfd(?P<bfd>) + (\sminimum-interval\s(?P<minimum_interval>\d+))? + (\smultiplier\s(?P<multiplier>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_bfd, + "result": { + "processes": { + "{{ pid }}": { + "bfd": { + "minimum_interval": "{{ minimum_interval|int }}", + "multiplier": "{{ multiplier|int }}", + }, + }, + }, + }, + }, + { + "name": "bfd.fast_detect", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \sfast-detect(?P<fast_detect>) + (\s(?P<disable>disable))? + (\s(?P<strict_mode>strict-mode))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_bfd_fast_detect, + "result": { + "processes": { + "{{ pid }}": { + "bfd": { + "fast_detect": { + "set": "{{ True if disable is undefined and strict_mode is undefined }}", + "strict_mode": "{{ True if strict_mode is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "security", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \ssecurity(?P<security>) + \sttl(?P<ttl>)? + (\shops\s(?P<hops>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_security, + "result": { + "processes": { + "{{ pid }}": { + "security_ttl": { + "set": "{{ True if ttl is defined and hops is undefined }}", + "hops": "{{ hops }}", + }, + }, + }, + }, + }, + { + "name": "nsr", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \snsr(?P<nsr>) + \sdisable(?P<disable>)? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_nsr, + "result": { + "processes": { + "{{ pid }}": { + "nsr": { + "set": "{{ True if nsr is defined and disable is undefined }}", + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + { + "name": "protocol", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sprotocol(?P<protocol>) + \s(shutdown(?P<shutdown>)) + (\shost-mode(?P<host_mode>))? + (\son-reload\s(?P<on_reload>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_protocol, + "result": { + "processes": { + "{{ pid }}": { + "protocol_shutdown": { + "set": "{{ True if shutdown is defined and host-mode is undefined and on_reload is undefined }}", + "host_mode": "{{ True if host_mode is defined }}", + "on_reload": "{{ True if on_reload is defined }}", + }, + }, + }, + }, + }, + { + "name": "capability", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \scapability(?P<capability>) + (\stype7\s(?P<type7>\S+))? + $""", + re.VERBOSE, + ), + "setval": "capability type7 {{ type7 }}", + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "type7": "{{ type7 }}", + }, + }, + }, + }, + }, + { + "name": "capability.opaque", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \scapability(?P<capability>)? + \sopaque(?P<opaque>) + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_capability_opaque, + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "opaque": { + "disable": "{{ True if disable is defined }}", + "set": "{{ True if opaque is defined and disable is undefined }}", + }, + }, + }, + }, + }, + }, + { + "name": "admin_distance", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdistance\s(?P<value>d+) + \s(?P<source>\S+) + \s(?P<wildcard>\S+) + (\s(?P<access_list>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_distance_admin, + "result": { + "processes": { + "{{ pid }}": { + "distance": { + "admin_distance": { + "value": "{{ value|int }}", + "source": "{{ source }}", + "wildcard": "{{ wildcard }}", + "access_list": "{{ access_list }}", + }, + }, + }, + }, + }, + }, + + { + "name": "ospf_distance", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdistance(?P<value>) + \sospf(?P<ospf>) + (\sexternal\s(?P<external>\d+))? + (\sinter-area\s(?P<inter_area>\d+))? + (\sintra-area\s(?P<intra_area>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_distance_ospf, + "result": { + "processes": { + "{{ pid }}": { + "distance": { + "ospf_distance": { + "external": "{{ external|int }}", + "inter_area": "{{ inter_area|int }}", + "intra_area": "{{ intra_area|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "authentication_key", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sauthentication-key(?P<auth_key>) + (\s(?P<password>\S+))? + (\sclear\s(?P<clear>)\S+)? + (\sencrypted(?P<encrypted>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_key, + "result": { + "processes": { + "{{ pid }}": { + "authentication_key": { + "clear": "{{ clear }}", + "encrypted": "{{ encrypted}}", + "password": "{{ password if clear is undefined and encrypted is undefined }}", + }, + }, + }, + }, + }, + { + "name": "area.default_cost", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdefault-cost\s(?P<default_cost>\d+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} default-cost {{ default_cost }}", + "compval": "default_cost", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "default_cost": "{{ default_cost|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.dead_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdead-interval\s(?P<dead_interval>\d+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} dead-interval {{ dead_interval }}", + "compval": "dead_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "dead_interval": "{{ dead_interval|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.hello_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \shello-interval\s(?P<hello_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} hello-interval {{ hello_interval }}", + "compval": "hello_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "hello_interval": "{{ hello_interval|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.transmit_delay", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \stransmit-delay\s(?P<transmit_delay>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} transmit-delay {{ transmit_delay }}", + "compval": "transmit_delay", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "transmit_delay": "{{ transmit_delay|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.cost", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \scost\s(?P<cost>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} cost {{ cost }}", + "compval": "cost", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "cost": "{{ cost|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.priority", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spriority\s(?P<priority>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} priority {{ priority }}", + "compval": "priority", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "priority": "{{ priority|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.weight", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sweight\s(?P<weight>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} weight {{ weight }}", + "compval": "weight", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "weight": "{{ weight|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.packet_size", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spacket-size\s(?P<packet_size>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} packet-size {{ packet_size }}", + "compval": "packet_size", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "packet_size": "{{ packet_size|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.summary_in", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \ssummary-in\s(?P<summary_in>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} summary-in {{ summary_in }}", + "compval": "summary_in", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "summary_in": "{{ summary_in }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.demand_circuit", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdemand-circuit\s(?P<demand_circuit>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} demand-circuit {{ demand_circuit }}", + "compval": "demand_circuit", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "demand_circuit": "{{ demand_circuit }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.passive", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spassive\s(?P<passive>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} passive {{ passive }}", + "compval": "passive", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "passive": "{{ passive }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.external_out", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sexternal-out\s(?P<external_out>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} external-out {{ external_out }}", + "compval": "passive", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "external_out": "{{ external_out }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.mtu_ignore", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smtu-ignore\s(?P<mtu_ignore>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} mtu-ignore {{ mtu_ignore }}", + "compval": "mtu_ignore", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mtu_ignore": "{{ mtu_ignore }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.authentication", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sauthentication(?P<auth>) + (\skeychain\s(?P<keychain>\S+))? + (\snull(?P<no_auth>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_authentication, + "compval": "authentication", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "no_auth": "{{ True if no_auth is defined }}", + "keychain": "{{ keychain }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.authentication_key", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sauthentication-key(?P<auth_key>) + (\s(?P<password>\S+))? + (\sclear\s(?P<clear>)\S+)? + (\sencrypted(?P<encrypted>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_authentication_key, + "compval": "authentication_key", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication_key": { + "clear": "{{ clear }}", + "encrypted": "{{ encrypted}}", + "password": "{{ password if clear is undefined and encrypted is undefined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.authentication.message_digest", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sauthentication(?P<auth>) + \smessage-digest(?P<md>) + \skeychain(?P<md_key>\s\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_authentication_md, + "compval": "authentication.message_digest", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "message_digest": { + "keychain": "{{ md_key }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.mpls_traffic_eng", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smpls(?P<mpls>) + \straffic-end(?P<traffic_eng>) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} mpls traffic-eng", + "compval": "mpls_traffic_eng", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mpls": { + "traffic_eng": "{{ True if traffic_eng is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.mpls_ldp", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smpls(?P<mpls>) + (\sauto-config(?P<auto_config>))? + (\ssync(?P<sync>))? + (\ssync-igp-shortcuts(?P<syn_igp_shortcuts>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_mpls_ldp, + "compval": "mpls_ldp", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mpls": { + "ldp": { + "auto_config": "{{ True if auto_config is defined }}", + "sync": "{{ True if sync is defined }}", + "sync_igp_shortcuts": "{{ True if sync_igp_shortcuts is defined }}", + + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.bfd", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sbfd(?P<bfd>) + (\sminimum-interval\s(?P<minimum_interval>\d+))? + (\smultiplier\s(?P<multiplier>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_bfd, + "compval": "bfd", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "bfd": { + "minimum_interval": "{{ minimum_interval|int }}", + "multiplier": "{{ multiplier|int }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.bfd.fast_detect", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \sarea(?P<area_id>) + \sfast-detect(?P<fast_detect>) + (\s(?P<disable>disable))? + (\s(?P<strict_mode>strict-mode))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_bfd_fast_detect, + "compval": "bfd.fast_detect", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "bfd": { + "fast_detect": { + "set": "{{ True if disable is undefined and strict_mode is undefined }}", + "strict_mode": "{{ True if strict_mode is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.stub", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sstub(?P<nssa>) + (\sno-summary(?P<no_sum>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_stub, + "compval": "stub", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "stub": { + "set": "{{ True if stub is defined and no_summary is undefined }}", + "no_summary": "{{ True if no_summary is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + (\sno-redistribution(?P<no_redis>))? + (\sno-summary(?P<no_sum>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa, + "compval": "nssa", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "nssa": { + "set": "{{ True if nssa is defined and no_summary is undefined and no_redis is undefined }}", + "no_summary": "{{ True if no_summary is defined }}", + "no_redistribution": "{{ True if no_redis is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa.default_information_originate", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + (\sno-redistribution(?P<no_redis>))? + (\sdefault-information-originate(?P<def_info_origin>))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa_def_info_origin, + "compval": "nssa.default_information_originate", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "nssa": { + "default_information_originate": { + "metric": "{{ metric|int }}", + "metric_type": "{{ metric_type|int }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.ranges", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \srange(?P<range>) + \s(?P<address>\S+) + (\sadvertise(?P<advertise>)) + (\snot-advertise(?P<not_advertise>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_ranges, + "compval": "ranges", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "ranges": [ + { + "address": "{{ address }}", + "advertise": "{{ True if advertise is defined }}", + "not_advertise": "{{ True if not_advertise is defined }}", + }, + ], + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa.translate", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + \stranslate(?P<translate>) + \stype7(?P<type7>) + \salways\s(?P<always>) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa_translate, + "compval": "nssa.translate", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "nssa": { + "translate": { + "type7": { + "always": "{{ True if always is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.hello_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \shello-interval\s(?P<hello_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} hello-interval {{ hello_interval }}", + "compval": "hello_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": + { + "id": "{{ id }}", + "hello_interval": "{{ hello_interval|int }}", + }, + + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.dead_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sdead-interval\s(?P<dead_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} dead-interval {{ dead_interval }}", + "compval": "dead_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "id": "{{ id }}", + "dead_interval": "{{ dead_interval|int }}", + }, + + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.retransmit_interval", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sretransmit-interval\s(?P<retransmit_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} retransmit-interval {{ retransmit_interval }}", + "compval": "retransmit_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "id": "{{ id }}", + "retransmit_interval": "{{ retransmit_interval|int }}", + }, + }, + + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \savirtual-link\s(?P<id>\S+) + \sauthentication(?P<auth>) + (\skeychain\s(?P<keychain>\S+))? + (\snull(?P<no_auth>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication, + "compval": "authentication", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "no_auth": "{{ True if no_auth is defined }}", + "keychain": "{{ keychain }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication_key", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sauthentication-key(?P<auth_key>) + (\s(?P<password>\S+))? + (\sclear\s(?P<clear>)\S+)? + (\sencrypted(?P<encrypted>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication_key, + "compval": "authentication_key", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "authentication_key": { + "clear": "{{ clear }}", + "encrypted": "{{ encrypted}}", + "password": "{{ password if clear is undefined and encrypted is undefined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication.message_digest", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sauthentication(?P<auth>) + \smessage-digest(?P<md>) + \skeychain(?P<md_key>\s\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication_md, + "compval": "authentication.message_digest", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "authentication": { + "message_digest": { + "keychain": "{{ md_key }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "link_down_fast_detect", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \slink-down + \sfast-detect(?P<fast_detect>) + $""", + re.VERBOSE, + ), + "setval": "link-down fast-detect", + "result": { + "processes": { + "{{ pid }}": { + "link_down_fast_detect": "{{ True if fast_detect is defined }}", + }, + }, + }, + }, + { + "name": "nsr", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \snsr + \sdisable(?P<disable>) + $""", + re.VERBOSE, + ), + "setval": "nsr disable", + "result": { + "processes": { + "{{ pid }}": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + { + "name": "database_filter", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdatabase-filter + \sall + \sout\s(?P<outing>\S+) + $""", + re.VERBOSE, + ), + + "setval": "database-filter all out {{ outing }}", + "result": { + "processes": { + "{{ pid }}": { + "outing": "{{ outing }}", + }, + }, + }, + }, + { + "name": "distribute_link_state", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdistribute(?P<distribute>) + \slink-state(?P<link_state>) + (\sinstance-id(?P<inst_id>\d+))? + (\sthrottle(?P<throttle>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_adjacency_distribute_bgp_state, + "result": { + "processes": { + "{{ pid }}": { + "distribute_link_list": { + "instance_id": "{{ inst_id|int }}", + "throttle": "{{ throttle }}", + }, + }, + }, + }, + }, + { + "name": "distribute_bgp_ls", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sdistribute(?P<distribute>) + \sbgp-ls(?P<bgp_ls>) + (\sinstance-id(?P<inst_id>\d+))? + (\sthrottle(?P<throttle>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_adjacency_distribute_bgp_state, + "result": { + "processes": { + "{{ pid }}": { + "distribute_bgp_ls": { + "instance_id": "{{ inst_id|int }}", + "throttle": "{{ throttle }}", + }, + }, + }, + }, + }, + { + "name": "log_adjacency_changes", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \slog(?P<security>) + \sadjacency(?P<adjacency>)? + (\schanges(?P<changes>))? + (\sdisable(?P<disable>))? + (\sdetails(?P<details>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_log_adjacency, + "result": { + "processes": { + "{{ pid }}": { + "log_adjacency_changes": { + "set": "{{ True if changes is defined }}", + "disable": "{{ True if disable is defined }}", + "details": "{{ True if details is defined }}", + }, + }, + }, + }, + }, + { + "name": "max_lsa", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + (\smax-lsa\s(?P<threshold>\d+))? + (\swarning-only\s(?P<warning_only>\d+)? + (\signore-time\s(?P<ignore_time>\d+))? + (\signore-count\s(?P<ignore_count>\d+))? + (\sreset-time\s(?P<reset_time>)\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_log_max_lsa, + "result": { + "processes": { + "{{ pid }}": { + "max_lsa": { + "threshold": "{{ threshold|int }}", + "warning_only": "{{ warning_only|int }}", + "ignore_time": "{{ ignore_time|int }}", + "ignore_count": "{{ ignore_count|int }}", + "reset_time": "{{ reset_time|int }}", + }, + }, + }, + }, + }, + { + "name": "max_metric", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \smax-metric + \s*(?P<router_lsa>) + (\s*external-lsa(?P<external_lsa>))? + (\s(?P<max_metric_value>\d+))? + \s*(?P<include_stub>include-stub)* + \s*(?P<on_startup>on-startup)* + \s*(?P<wait_period>\d+)* + \s*(wait-for\sbgp)* + \s*(?P<bgp_asn>\d+)* + \s*(?P<summary_lsa>summary-lsa)* + \s*(?P<sum_lsa_max_metric_value>\d+)* + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_max_metric, + "remval": "max-metric router-lsa", + "result": { + "processes": { + '{{ "pid" }}': { + "max_metric": { + "router_lsa": { + "set": "{{ True if router_lsa is defined and external_lsa is undefined else None }}", + "external_lsa": { + "set": "{{ True if external_lsa is defined and max_metric_value is undefined else None }}", + "max_metric_value": "{{ max_metric_value }}", + }, + "include_stub": "{{ not not include_stub }}", + "on_startup": { + "set": "{{ True if on_startup is defined and (wait_period and bgp_asn) is undefined else None }}", + "wait_period": "{{ wait_period }}", + "wait_for_bgp_asn": "{{ bgp_asn }}", + }, + "summary_lsa": { + "set": "{{ True if summary_lsa is defined and sum_lsa_max_metric_value is undefined else None }}", + "max_metric_value": "{{ sum_lsa_max_metric_value }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mpls_ldp", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \smpls(?P<mpls>) + (\sauto-config(?P<auto_config>))? + (\ssync(?P<sync>))? + (\ssync-igp-shortcuts(?P<syn_igp_shortcuts>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_mpls_ldp, + "compval": "mpls_ldp", + "result": { + "processes": { + "{{ pid }}": { + "mpls": { + "ldp": { + "auto_config": "{{ True if auto_config is defined }}", + "sync": "{{ True if sync is defined }}", + "sync_igp_shortcuts": "{{ True if sync_igp_shortcuts is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "microloop_avoidance", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \smicroloop(?P<microloop>) + \savoidance(?P<avoidance>) + (\s(?P<protected>protected))? + (\s(?P<segment_routing>segment-routing))? + (\srib-update-delay\s(?P<rib_update_delay>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_microloop_avoidance, + "compval": "microloop_avoidance", + "result": { + "processes": { + "{{ pid }}": { + "microloop_avoidance": { + "protected": "{{ True if protected is defined }}", + "segment_routing": "{{ True if segment_routing is defined }}", + "rib_update_delay": "{{ rib_update_delay }}", + }, + }, + }, + }, + }, + { + "name": "mpls_traffic_eng", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \smpls(?P<mpls>) + \straffic-end(?P<traffic_eng>) + (\sautoroute-exclude(?P<autoroute>))? + (\sroute-policy(?P<route_policy>\S+))? + (\s(?P<igp_intact>igp_intact))? + (\s(?P<ldp_sync_update>ldp-sync-update))? + (\s(?P<multicast_intact>multicast-intact))? + (\srouter-id\s(?P<router_id>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_mpls_traffic_eng, + "result": { + "processes": { + "{{ pid }}": { + "mpls": { + "autoroute_exclude": { + "route_policy": "{{ route_policy }}", + }, + "igp_intact": "{{ True if igp_intact is defined }}", + "ldp_sync_update": "{{ True if ldp_sync_update is defined }}", + "multicast_intact": "{{ True if multicast_intact is defined }}", + "router_id": "{{ router_id }}", + }, + }, + }, + }, + }, + { + "name": "prefix_suppression", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sprefix-suppression(?P<prefix_suppression>) + (\s(?P<secondary_address>secondary-address))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_prefix_suppression, + "result": { + "processes": { + "{{ pid }}": { + "prefix_suppression": { + "set": "{{ True if prefix_suppression is defined and secondary_address is undefined }}", + "secondary_address": "{{ True if secondary_address is defined }}", + }, + }, + }, + }, + }, + { + "name": "protocol_shutdown", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \sprotocol-shutdown(?P<protocol_shutdown>) + (\s(?P<host_mode>host-mode))? + (\s(?P<on_reload>on-reload))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_protocol_shutdown, + "result": { + "processes": { + "{{ pid }}": { + "protocol_shutdown": { + "set": "{{ True if protocol_shutdown is defined and host_mode is undefined and on_reload is undefined }}", + "host_mode": "{{ True if host_mode is defined }}", + "on_reload": "{{ True if on_reload is defined }}", + }, + }, + }, + }, + }, + { + "name": "timers.lsa", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \slsa + (\sgroup-pacing\s(?P<group_pacing>\d+))? + (\smin-arrival\s(?P<min_arrival>\d+))? + (\srefresh\s(?P<refresh>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_timers_lsa, + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "lsa": { + "group_pacing": "{{ group_pacing|int }}", + "min_arrival": "{{ min_arrival|int }}", + "refresh": "{{ refresh|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.graceful_shutdown", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \sgraceful_shutdown + (\sinitial delay\s(?P<initial_delay>\d+))? + (\sretain routes\s(?P<retain_routes>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_timers_graceful_shutdown, + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "graceful_shutdown": { + "initial_delay": "{{ initial_delay|int }}", + "retain_routes": "{{ retain_routes|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "throttle.spf", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \sthrottle + \sspf + (\s(?P<change_delay>\d+)) + (\s(?P<second_delay>\d+)) + (\s(?P<max_wait>\d+)) + $""", + re.VERBOSE, + ), + "setval": "timers throttle spf {{ throttle.spf.change_delay }} {{ throttle.spf.second_delay }} {{ throttle.spf.max_wait }}", + "compval": "throttle.lsa_all", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "lsa_all": { + "initial_delay": "{{ initial_delay }}", + "min_delay": "{{ min_delay }}", + "max_delay": "{{ max_delay }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "throttle.lsa_all", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \sthrottle + \slsa + \sall + (\s(?P<initial_delay>\d+)) + (\s(?P<min_delay>\d+)) + (\s(?P<max_delay>\d+)) + $""", + re.VERBOSE, + ), + "setval": "timers throttle lsa all {{ throttle.lsa_all.initial_delay }} {{ throttle.lsa_all.min_delay }} {{ throttle.lsa_all.max_delay }}", + "compval": "throttle.lsa_all", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "lsa_all": { + "initial_delay": "{{ initial_delay }}", + "min_delay": "{{ min_delay }}", + "max_delay": "{{ max_delay }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "throttle.fast_reroute", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \sthrottle + \sfast-reroute\s(?P<fast_reroute>\d+) + $""", + re.VERBOSE, + ), + "setval": "timers throttle fast-reroute {{ fast_reroute }}", + "compval": "throttle.fast_reroute", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "fast_reroute": "{{ fast_reroute }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.pacing_flood", + "getval": re.compile( + r""" + ^router + \sospf\s(?P<pid>\S+) + \stimers + \spacing + \sflood\s(?P<pacing_flood>\d+) + $""", + re.VERBOSE, + ), + "setval": "timers pacing flood {{ pacing_flood }}", + "compval": "timers.pacing_flood", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "pacing_flood": "{{ pacing_flood }}", + + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv3.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv3.py new file mode 100644 index 00000000..14e3720b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ospfv3.py @@ -0,0 +1,2779 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import re + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def _tmplt_ospf_default_information(config_data): + if "default_information_originate" in config_data: + command = "default-information originate" + if "always" in config_data["default_information_originate"]: + command += " always" + if "metric" in config_data["default_information_originate"]: + command += " metric {metric}".format(**config_data["default_information_originate"]) + if "metric_type" in config_data["default_information_originate"]: + command += " metric-type {metric_type}".format( + **config_data["default_information_originate"] + ) + if "route_policy" in config_data["default_information_originate"]: + command += " route-policy {route_policy}".format( + **config_data["default_information_originate"] + ) + return command + + +def _tmplt_ospf_auto_cost(config_data): + if "auto_cost" in config_data: + command = "auto-cost" + if "disable" in config_data["auto_cost"]: + command += " disable" + if "reference_bandwidth" in config_data["auto_cost"]: + command += " reference-bandwidth {reference_bandwidth}".format( + **config_data["auto_cost"] + ) + return command + + +def _tmplt_ospfv3_bfd_minimum_interval(config_data): + if "bfd" in config_data: + if "minimum_interval" in config_data["bfd"]: + command = "bfd minimum-interval {minimum_interval}".format(**config_data["bfd"]) + return command + + +def _tmplt_ospfv3_bfd_multiplier(config_data): + if "bfd" in config_data: + if "multiplier" in config_data["bfd"]: + command = "bfd multiplier {multiplier}".format(**config_data["bfd"]) + return command + + +def _tmplt_ospf_security(config_data): + if "security_ttl" in config_data: + command = "security_ttl" + if "set" in config_data["security_ttl"]: + command += " ttl" + elif config_data["security_ttl"].get("hops"): + command += " ttl hops {0}".format( + config_data["security_ttl"].get("hops"), + ) + return command + + +def _tmplt_ospf_log_adjacency(config_data): + if "log_adjacency_changes" in config_data: + command = "log adjacency" + if "set" in config_data["log_adjacency_changes"]: + command += " changes" + elif config_data["log_adjacency_changes"].get("disable"): + command += " disable" + elif config_data["log_adjacency_changes"].get("details"): + command += " details" + return command + + +def _tmplt_ospf_log_max_lsa(config_data): + if "max_lsa" in config_data: + command = "max-lsa" + if "threshold" in config_data["max_lsa"]: + command += " {0}".format(config_data["max_lsa"].get("threshold")) + if "warning_only" in config_data["max_lsa"]: + command += " warning-only {0}".format( + config_data["max_lsa"].get("warning_only"), + ) + if "ignore_time" in config_data["max_lsa"]: + command += " ignore-time {0}".format( + config_data["max_lsa"].get("ignore_time"), + ) + if "ignore_count" in config_data["max_lsa"]: + command += " ignore-count {0}".format( + config_data["max_lsa"].get("ignore_count"), + ) + if "reset_time" in config_data["max_lsa"]: + command += " reset-time {0}".format( + config_data["max_lsa"].get("reset_time"), + ) + return command + + +def _tmplt_ospf_max_metric(config_data): + if "max_metric" in config_data: + command = "max-metric" + if "router_lsa" in config_data["max_metric"]: + command += " router-lsa" + if "external_lsa" in config_data["max_metric"]: + command += " external-lsa {external_lsa}".format(**config_data["max_metric"]) + if "include_stub" in config_data["max_metric"]: + command += " include-stub" + if "on_startup" in config_data["max_metric"]: + if "time" in config_data["max_metric"]["on_startup"]: + command += " on-startup {time}".format(**config_data["max_metric"]["on_startup"]) + elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]: + command += " on-startup wait-for-bgp" + if "summary_lsa" in config_data["max_metric"]: + command += " summary-lsa {summary_lsa}".format(**config_data["max_metric"]) + return command + + +def _tmplt_ospf_distance_admin(config_data): + if "admin_distance" in config_data: + command = "distance" + if config_data["admin_distance"].get("value"): + command += " {0}".format( + config_data["admin_distance"].get("value"), + ) + if config_data["admin_distance"].get("source"): + command += " {0}".format( + config_data["admin_distance"].get("source"), + ) + if config_data["admin_distance"].get("wildcard"): + command += " {0}".format( + config_data["admin_distance"].get("wildcard"), + ) + if config_data["admin_distance"].get("access_list"): + command += " {0}".format( + config_data["admin_distance"].get("access_list"), + ) + return command + + +def _tmplt_ospf_distance_ospf(config_data): + if "ospf_distance" in config_data: + command = "distance ospf" + if config_data["ospf_distance"].get("external"): + command += " external {0}".format( + config_data["ospf_distance"].get("external"), + ) + if config_data["ospf_distance"].get("inter_area"): + command += " inter-area {0}".format( + config_data["ospf_distance"].get("inter_area"), + ) + if config_data["ospf_distance"].get("intra_area"): + command += " intra-area {0}".format( + config_data["ospf_distance"].get("intra_area"), + ) + return command + + +def _tmplt_ospf_nsr(config_data): + if "nsr" in config_data: + command = "nsr" + if "set" in config_data["nsr"]: + command += " nsr" + elif config_data["nsr"].get("disable"): + command += " nsr {0}".format("disable") + return command + + +def _tmplt_ospf_protocol(config_data): + if "protocol_shutdown" in config_data: + command = "protocol" + if "set" in config_data["protocol_shutdown"]: + command += " shutdown" + elif config_data["shutdown"].get("host_mode"): + command += " shutdown host-mode" + elif config_data["shutdown"].get("on_reload"): + command += " shutdown on-reload" + return command + + +def _tmplt_microloop_avoidance(config_data): + if "microloop_avoidance" in config_data: + command = "microloop avoidance" + if "protected" in config_data["microloop_avoidance"]: + command += " protected" + if "segment_routing" in config_data["microloop_avoidance"]: + command += " segment_routing" + if "rib_update_delay" in config_data["microloop_avoidance"]: + command += " rin-update-delay {0}".config_data["microloop_avoidance"].get( + "rib_update_delay", + ) + return command + + +def _tmplt_ospf_bfd_fast_detect(config_data): + if "bfd" in config_data: + if "fast_detect" in config_data["bfd"]: + command = "bfd" + fast_detect = config_data["bfd"].get("fast_detect") + command += " fast-detect" + if "strict_mode" in fast_detect: + command += " strict-mode" + return command + + +def _tmplt_ospf_mpls_traffic_eng(config_data): + if "traffic_eng" in config_data: + command = "mpls traffic-eng" + if "igp_intact" in config_data["traffic_eng"]: + command += " igp-intact" + if "ldp_sync_update" in config_data["traffic_eng"]: + command += " ldp_sync_update" + if "multicast_intact" in config_data["traffic_eng"]: + command += " multicast_intact" + if "auto_route_exclude" in config_data["traffic_eng"]: + policy = config_data["traffic_eng"].get("autoroute_exclude") + command += " autoroute-exlude route-policy {0}".format( + policy.get("route_policy"), + ) + return command + + +def _tmplt_ospf_authentication_ipsec(config_data): + if "authentication" in config_data: + if config_data["authentication"].get("ipsec"): + command = "authentication ipsec" + md = config_data["authentication"].get("ipsec") + if md.get("spi"): + command += " spi " + str(md.get("spi")) + if md.get("algorithim_type"): + command += " " + md.get("algorithim_type") + if md.get("clear_key"): + command += " clear " + md.get("clear_key") + elif md.get("password_key"): + command += " password " + md.get("password_key") + elif md.get("key"): + command += " " + md.get("key") + return command + + +def _tmplt_ospfv3_demand_circuit(config_data): + if "demand_circuit" in config_data: + command = "demand-circuit" + return command + + +def _tmplt_ospfv3_passive(config_data): + if "passive" in config_data: + command = "passive" + return command + + +def _tmplt_ospfv3_demand_mtu_ignore(config_data): + if "mtu_ignore" in config_data: + command = "mtu-ignore" + return command + + +def _tmplt_ospfv3_authentication(config_data): + if "authentication" in config_data: + if config_data["authentication"].get("disable"): + command = "authentication disable" + return command + + +def _tmplt_ospf_adjacency_distribute_bgp_state(config_data): + if "distribute_link_list" in config_data: + command = "distribute link-state" + if config_data["distribute_link_list"].get("instance_id"): + command += " instance-id {0}".format( + config_data["distribute_link_list"].get("instance_id"), + ) + elif config_data["distribute_link_list"].get("throttle"): + command += " throttle {0}".format( + config_data["distribute_link_list"].get("throttle"), + ) + return command + elif "distribute_bgp_ls" in config_data: + command = "distribute bgp-ls" + if config_data["distribute_bgp_ls"].get("instance_id"): + command += " instance-id {0}".format( + config_data["distribute_bgp_ls"].get("instance_id"), + ) + elif config_data["distribute_bgp_ls"].get("throttle"): + command += " throttle {0}".format( + config_data["distribute_bgp_ls"].get("throttle"), + ) + return command + + +def _tmplt_ospf_capability_opaque(config_data): + if "capability" in config_data: + if "opaque" in config_data["capability"]: + command = "capability opaque" + opaque = config_data["capability"].get("opaque") + if "disable" in opaque: + command += "capability opaque disable" + return command + + +def _tmplt_ospfv3_area_authentication(config_data): + if "authentication" in config_data: + if config_data["authentication"].get("disable"): + command = "area {area_id} ".format(**config_data) + command += "authentication disable" + return command + + +def _tmplt_ospfv3_area_authentication_ipsec(config_data): + if "authentication" in config_data: + command = "area {area_id} ".format(**config_data) + if config_data["authentication"].get("ipsec"): + command += "authentication ipsec" + md = config_data["authentication"].get("ipsec") + if md.get("spi"): + command += " spi " + str(md.get("spi")) + if md.get("algorithim_type"): + command += " " + md.get("algorithim_type") + if md.get("clear_key"): + command += " clear " + md.get("clear_key") + elif md.get("password_key"): + command += " password " + md.get("password_key") + elif md.get("key"): + command += " " + md.get("key") + return command + + +def _tmplt_ospf_area_mpls_ldp(config_data): + commands = [] + if "mpls" in config_data: + command = "area {area_id} mpls".format(**config_data) + if config_data["mpls"].get("ldp"): + ldp = config_data["mpls"].get("ldp") + if "auto_config" in ldp: + command += " auto-config" + commands.append(command) + if "sync" in ldp: + command += " sync" + commands.append(command) + if "sync_igp_shortcuts" in ldp: + command += " sync-igp-shortcuts" + commands.append(command) + return commands + + +def _tmplt_ospfv3_area_bfd_minimum_interval(config_data): + if "bfd" in config_data: + if "minimum_interval" in config_data["bfd"]: + command = "area {area_id} ".format(**config_data) + command += " bfd minimum-interval {minimum_interval}".format(**config_data["bfd"]) + return command + + +def _tmplt_ospfv3_area_bfd_multiplier(config_data): + if "bfd" in config_data: + if "multiplier" in config_data["bfd"]: + command = "area {area_id} ".format(**config_data) + command += "bfd multiplier {multiplier}".format(**config_data["bfd"]) + return command + + +def _tmplt_ospfv3_area_bfd_fast_detect(config_data): + if "bfd" in config_data: + if "fast_detect" in config_data["bfd"]: + command = "area {area_id} ".format(**config_data) + fast_detect = config_data["bfd"].get("fast_detect") + command += "bfd fast-detect" + if "strict_mode" in fast_detect: + command += " strict-mode" + return command + + +def _tmplt_ospf_mpls_ldp(config_data): + commands = [] + if "mpls" in config_data: + command = "mpls".format(**config_data) + if config_data["mpls"].get("ldp"): + ldp = config_data["mpls"].get("ldp") + if "auto_config" in ldp: + command += " auto-config" + commands.append(command) + if "sync" in ldp: + command += " sync" + commands.append(command) + if "sync_igp_shortcuts" in ldp: + command += " sync-igp-shortcuts" + commands.append(command) + return commands + + +def _tmplt_ospf_area_nssa(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if config_data["nssa"].get("no_redistribution"): + command += " no-redistribution" + if config_data["nssa"].get("no_summary"): + command += " no-summary" + return command + + +def _tmplt_ospf_area_nssa_def_info_origin(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if "default_information_originate" in config_data["nssa"]: + command += " default-information-originate" + def_info_origin = config_data["nssa"].get( + "default_information_originate", + ) + if "metric" in def_info_origin: + command += " metric {metric}".format( + **config_data["nssa"]["default_information_originate"] + ) + if "metric_type" in def_info_origin: + command += " metric-type {metric_type}".format( + **config_data["nssa"]["default_information_originate"] + ) + return command + + +def _tmplt_ospf_area_nssa_translate(config_data): + if "nssa" in config_data: + command = "area {area_id} nssa".format(**config_data) + if config_data["nssa"].get("translate"): + command += " translate" + translate = config_data["nssa"].get("translate") + if "type7" in translate: + command += " type7" + if translate["type7"].get("always"): + command += " always" + return command + + +def _tmplt_ospf_area_vlink_authentication(config_data): + if "authentication" in config_data: + command = "area {area_id} virtual-link {id} authentication".format(**config_data) + if config_data["authentication"].get("keychain"): + command += " keychain " + config_data["authentication"].get( + "keychain", + ) + elif config_data["authentication"].get("no_auth"): + command += " null" + return command + + +def _tmplt_ospf_area_vlink_authentication_md(config_data): + if "authentication" in config_data: + command = "area {area_id} virtual-link {id} authentication".format(**config_data) + if config_data["authentication"].get("message_digest"): + command = "authentication message-digest" + md = config_data["authentication"].get("message_digest") + if md.get("keychain"): + command += " keychain " + md.get("keychain") + return command + + +def _tmplt_ospf_area_vlink_authentication_key(config_data): + if "authentication_key" in config_data: + command = "area {area_id} virtual-link {id} authentication-key".format(**config_data) + if config_data["authentication_key"].get("password"): + command += " {0}".format( + config_data["authentication_key"].get("password"), + ) + return command + + +def _tmplt_ospf_area_stub(config_data): + if "stub" in config_data: + command = "area {area_id} stub".format(**config_data) + if config_data["stub"].get("no_summary"): + command += " no-summary" + return command + + +def _tmplt_ospf_area_ranges(config_data): + if "ranges" in config_data: + commands = [] + for k, v in iteritems(config_data["ranges"]): + cmd = "area {area_id} range".format(**config_data) + temp_cmd = " {address}".format(**v) + if "advertise" in v: + temp_cmd += " advertise" + elif "not_advertise" in v: + temp_cmd += " not-advertise" + cmd += temp_cmd + commands.append(cmd) + return commands + + +def _tmplt_prefix_suppression(config_data): + if "prefix_suppression" in config_data: + if "set" in config_data["prefix_suppression"]: + command = "prefix-suppression" + if "secondary_address" in config_data["prefix_suppression"]: + command = "prefix-suppression secondary-address" + return command + + +def _tmplt_protocol_shutdown(config_data): + if "protocol_shutdown" in config_data: + if "set" in config_data["protocol_shutdown"]: + command = "protocol-shutdown" + if "host_mode" in config_data["protocol_shutdown"]: + command = "protocol-shutdown host-mode" + if "on_reload" in config_data["protocol_shutdown"]: + command = "protocol-shutdown on-reload" + return command + + +def _tmplt_timers_lsa(config_data): + if "timers" in config_data: + command = "timers lsa" + if "group_pacing" in config_data["timers"]["lsa"]: + command += " group-pacing {group_pacing}".format(**config_data["timers"]["lsa"]) + if "min_arrival" in config_data["timers"]["lsa"]: + command += " min-arrival {min_arrival}".format(**config_data["timers"]["lsa"]) + if "refresh" in config_data["timers"]["lsa"]: + command += " refresh {refresh}".format(**config_data["timers"]["lsa"]) + return command + + +def _tmplt_timers_graceful_shutdown(config_data): + if "timers" in config_data: + command = "timers graceful-shutdown" + if "initial_delay" in config_data["timers"]["graceful-shutdown"]: + command += " initial delay {initial_delay}".format( + **config_data["timers"]["graceful-shutdown"] + ) + if "retain_routes" in config_data["timers"]["graceful-shutdown"]: + command += " retain routes {retain_routes}".format( + **config_data["timers"]["graceful-shutdown"] + ) + return command + + +class Ospfv3Template(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Ospfv3Template, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "pid", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + $""", + re.VERBOSE, + ), + "setval": "router ospfv3 {{ process_id }}", + "result": { + "processes": {"{{ pid }}": {"process_id": "{{ pid }}"}}, + }, + "shared": True, + }, + { + "name": "cost", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \scost(?P<cost>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "cost {{ cost }}", + "result": { + "processes": { + "{{ pid }}": { + "cost": "{{ cost|int }}", + }, + }, + }, + }, + { + "name": "default_metric", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdefault-metric(?P<default_metric>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "default-metric {{ default_metric }}", + "result": { + "processes": { + "{{ pid }}": { + "default_metric": "{{ default_metric|int }}", + }, + }, + }, + }, + { + "name": "packet_size", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \spacket-size(?P<packet_size>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "packet-size {{ packet_size }}", + "result": { + "processes": { + "{{ pid }}": { + "packet_size": "{{ packet_size|int }}", + }, + }, + }, + }, + { + "name": "dead_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdead-interval(?P<dead_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "dead-interval {{ dead_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "dead_interval": "{{ dead_interval|int }}", + }, + }, + }, + }, + { + "name": "hello_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \shello-interval(?P<hello_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "hello-interval {{ hello_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "hello_interval": "{{ hello_interval|int }}", + }, + }, + }, + }, + { + "name": "priority", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \spriority(?P<priority>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "priority {{ priority }}", + "result": { + "processes": { + "{{ pid }}": { + "priority": "{{ priority|int }}", + }, + }, + }, + }, + { + "name": "weight", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sweight(?P<weight>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "weight {{ weight }}", + "result": { + "processes": { + "{{ pid }}": { + "weight": "{{ weight|int }}", + }, + }, + }, + }, + { + "name": "retransmit_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sretransmit-interval(?P<retransmit_interval>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "retransmit-interval {{ retransmit_interval }}", + "result": { + "processes": { + "{{ pid }}": { + "retransmit_interval": "{{ retransmit_interval|int }}", + }, + }, + }, + }, + { + "name": "transmit_delay", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stransmit-delay(?P<transmit_delay>\s\d+) + $""", + re.VERBOSE, + ), + + "setval": "transmit-delay {{ transmit_delay }}", + "result": { + "processes": { + "{{ pid }}": { + "transmit_delay": "{{ transmit_delay|int }}", + }, + }, + }, + }, + { + "name": "passive", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + (\spassive(?P<passive>))? + $""", + re.VERBOSE, + ), + + "setval": _tmplt_ospfv3_passive, + "result": { + "processes": { + "{{ pid }}": { + "passive": "{{ True if passive is defined }}", + }, + }, + }, + }, + { + "name": "process.database_filter", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdatabase-filter + \sall + \sout\s(?P<database_filter>\s\S+) + $""", + re.VERBOSE, + ), + + "setval": "process.database_filter", + "result": { + "processes": { + "{{ pid }}": { + "database_filter": "{{ database_filter }}", + }, + }, + }, + }, + { + "name": "demand_circuit", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + (\sdemand-circuit(?P<demand_circuit>))? + $""", + re.VERBOSE, + ), + + "setval": _tmplt_ospfv3_demand_circuit, + "result": { + "processes": { + "{{ pid }}": { + "demand_circuit": "{{ True if demand_circuit is defined }}", + }, + }, + }, + }, + { + "name": "router_id", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \srouter-id\s(?P<router_id>\S+) + $""", + re.VERBOSE, + ), + + "setval": "router-id {{ router_id }}", + "result": { + "processes": { + "{{ pid }}": { + "router_id": "{{ router_id }}", + }, + }, + }, + }, + { + "name": "mtu_ignore", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + (\smtu-ignore(?P<mtu_ignore>))? + $""", + re.VERBOSE, + ), + + "setval": _tmplt_ospfv3_demand_mtu_ignore, + "result": { + "processes": { + "{{ pid }}": { + "mtu_ignore": "{{ True if mtu_ignore is defined }}", + }, + }, + }, + }, + { + "name": "flood_reduction", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sflood-reduction\s(?P<flood_reduction>\S+) + $""", + re.VERBOSE, + ), + + "setval": "flood-reduction {{ True if flood_reduction is defined }}", + "result": { + "processes": { + "{{ pid }}": { + "flood_reduction": "{{ flood_reduction }}", + }, + }, + }, + }, + { + "name": "loopback_stub_network", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sloopback(?P<loopback>) + \sstub-network\s(?P<stub_network>\S+) + $""", + re.VERBOSE, + ), + + "setval": "loopback stub-network {{ stub_network }}", + "result": { + "processes": { + "{{ pid }}": { + "loopback_stub_network": "{{ loopback_stub_network }}", + }, + }, + }, + }, + { + "name": "address_family_unicast", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \saddress-family(?P<address_family>) + \sipv4(?P<ipv4>) + \sunicast(?P<unicast>) + $""", + re.VERBOSE, + ), + + "setval": "address_family_unicast", + "result": { + "processes": { + "{{ pid }}": { + "address_family_unicast": "{{ True if unicast is defined }}", + }, + }, + }, + }, + { + "name": "default_weight", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sapply-weight(?P<apply_weight>) + \sdefault-weight(?P<default_weight>\s\d+) + $""", + re.VERBOSE, + ), + "setval": "apply-weight default-weight {{ default_weight }}", + "result": { + "processes": { + "{{ pid }}": { + "apply_weight": { + "default_weight": "{{ default_weight|int }}", + }, + }, + }, + }, + }, + { + "name": "bandwidth", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sapply-weight(?P<apply_weight>) + \sbandwidth(?P<bandwidth>\s\d+)? + $""", + re.VERBOSE, + ), + "setval": "apply-weight bandwidth {{ bandwidth }}", + "result": { + "processes": { + "{{ pid }}": { + "apply_weight": { + "bandwidth": "{{ bandwidth|int }}", + }, + }, + }, + }, + }, + { + "name": "authentication", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sauthentication(?P<auth>) + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_authentication, + "result": { + "processes": { + "{{ pid }}": { + "authentication": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + { + "name": "authentication.ipsec", + "getval": re.compile( + r"""^router + \sospfv3\s(?P<pid>\S+) + \sauthentication(?P<auth>) + \sipsec(?P<ipsec>) + \sspi\s(?P<spi>\d+) + (\s(?P<algo_type>\S+))? + (\spassword\s(?P<password_key>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_authentication_ipsec, + "result": { + "processes": { + "{{ pid }}": { + "authentication": { + "ipsec": { + "spi": "{{ spi }}", + "algorithim_type": "{{ algo_type }}", + "clear_key": "{{ clear_key }}", + "password_key": "{{ password_key }}", + "key": "{{ key }}", + }, + }, + }, + }, + }, + }, + { + "name": "default_information_originate", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdefault-information(?P<default_information>) + (\soriginate(?P<originate>))? + (\salways(?P<always>))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + (\sroute_policy\s(?P<route_policy>)\S+)? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_default_information, + "result": { + "processes": { + "{{ pid }}": { + "default_information_originate": { + "always": "{{ True if always is defined }}", + "metric": "{{ metric|int }}", + "metric_type": "{{ metric_type|int }}", + "route_policy": "{{ route_policy }}", + "set": "{{ True if default_information is defined and always is undefined and metric " + "is undefined and metric_type is undefined and route_policy is undefined }}", + }, + }, + }, + }, + }, + { + "name": "auto_cost", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sauto-cost(?P<auto_cost>) + (\sreference-bandwidth\s(?P<reference_bandwidth>\d+))? + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_auto_cost, + "result": { + "processes": { + "{{ pid }}": { + "auto_cost": { + "disable": "{{ True if disable is defined }}", + "reference_bandwidth": "{{ reference_bandwidth|int }}", + }, + }, + }, + }, + }, + { + "name": "bfd.minimum_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \sminimum-interval\s(?P<minimum_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_bfd_minimum_interval, + "result": { + "processes": { + "{{ pid }}": { + "bfd": { + "minimum_interval": "{{ minimum_interval|int }}", + }, + }, + }, + }, + }, + { + "name": "bfd.multiplier", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \smultiplier\s(?P<multiplier>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_bfd_multiplier, + "result": { + "processes": { + "{{ pid }}": { + "bfd": { + "multiplier": "{{ multiplier|int }}", + }, + }, + }, + }, + }, + { + "name": "bfd.fast_detect", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \sfast-detect(?P<fast_detect>) + (\s(?P<disable>disable))? + (\s(?P<strict_mode>strict-mode))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_bfd_fast_detect, + "result": { + "processes": { + "{{ pid }}": { + "bfd": { + "fast_detect": { + "set": "{{ True if disable is undefined and strict_mode is undefined }}", + "strict_mode": "{{ True if strict_mode is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "security", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \ssecurity(?P<security>) + \sttl(?P<ttl>)? + (\shops\s(?P<hops>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_security, + "result": { + "processes": { + "{{ pid }}": { + "security_ttl": { + "set": "{{ True if ttl is defined and hops is undefined }}", + "hops": "{{ hops }}", + }, + }, + }, + }, + }, + { + "name": "nsr", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \snsr(?P<nsr>) + \sdisable(?P<disable>)? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_nsr, + "result": { + "processes": { + "{{ pid }}": { + "nsr": { + "set": "{{ True if nsr is defined and disable is undefined }}", + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + { + "name": "protocol", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sprotocol(?P<protocol>) + \s(shutdown(?P<shutdown>)) + (\shost-mode(?P<host_mode>))? + (\son-reload\s(?P<on_reload>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_protocol, + "result": { + "processes": { + "{{ pid }}": { + "protocol_shutdown": { + "set": "{{ True if shutdown is defined and host-mode is undefined and on_reload is undefined }}", + "host_mode": "{{ True if host_mode is defined }}", + "on_reload": "{{ True if on_reload is defined }}", + }, + }, + }, + }, + }, + { + "name": "capability", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \scapability(?P<capability>) + (\stype7\s(?P<type7>\S+))? + $""", + re.VERBOSE, + ), + "setval": "capability type7 {{ type7 }}", + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "type7": "{{ type7 }}", + }, + }, + }, + }, + }, + { + "name": "capability.opaque", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \scapability(?P<capability>)? + \sopaque(?P<opaque>) + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_capability_opaque, + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "opaque": { + "disable": "{{ True if disable is defined }}", + "set": "{{ True if opaque is defined and disable is undefined }}", + }, + }, + }, + }, + }, + }, + { + "name": "admin_distance", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdistance\s(?P<value>d+) + \s(?P<source>\S+) + \s(?P<wildcard>\S+) + (\s(?P<access_list>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_distance_admin, + "result": { + "processes": { + "{{ pid }}": { + "distance": { + "admin_distance": { + "value": "{{ value|int }}", + "source": "{{ source }}", + "wildcard": "{{ wildcard }}", + "access_list": "{{ access_list }}", + }, + }, + }, + }, + }, + }, + + { + "name": "ospf_distance", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdistance(?P<value>) + \sospfv3(?P<ospf>) + (\sexternal\s(?P<external>\d+))? + (\sinter-area\s(?P<inter_area>\d+))? + (\sintra-area\s(?P<intra_area>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_distance_ospf, + "result": { + "processes": { + "{{ pid }}": { + "distance": { + "ospf_distance": { + "external": "{{ external|int }}", + "inter_area": "{{ inter_area|int }}", + "intra_area": "{{ intra_area|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.default_cost", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdefault-cost\s(?P<default_cost>\d+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} default-cost {{ default_cost }}", + "compval": "default_cost", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "default_cost": "{{ default_cost|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.dead_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdead-interval\s(?P<dead_interval>\d+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} dead-interval {{ dead_interval }}", + "compval": "dead_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "dead_interval": "{{ dead_interval|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.hello_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \shello-interval\s(?P<hello_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} hello-interval {{ hello_interval }}", + "compval": "hello_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "hello_interval": "{{ hello_interval|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.transmit_delay", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \stransmit-delay\s(?P<transmit_delay>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} transmit-delay {{ transmit_delay }}", + "compval": "transmit_delay", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "transmit_delay": "{{ transmit_delay|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.cost", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \scost\s(?P<cost>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} cost {{ cost }}", + "compval": "cost", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "cost": "{{ cost|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.priority", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spriority\s(?P<priority>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} priority {{ priority }}", + "compval": "priority", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "priority": "{{ priority|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.weight", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sweight\s(?P<weight>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} weight {{ weight }}", + "compval": "weight", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "weight": "{{ weight|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.packet_size", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spacket-size\s(?P<packet_size>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} packet-size {{ packet_size }}", + "compval": "packet_size", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "packet_size": "{{ packet_size|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.summary_in", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \ssummary-in\s(?P<summary_in>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} summary-in {{ summary_in }}", + "compval": "summary_in", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "summary_in": "{{ summary_in }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.demand_circuit", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sdemand-circuit\s(?P<demand_circuit>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} demand-circuit {{ demand_circuit }}", + "compval": "demand_circuit", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "demand_circuit": "{{ demand_circuit }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.passive", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \spassive\s(?P<passive>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} passive {{ passive }}", + "compval": "passive", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "passive": "{{ passive }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.external_out", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sexternal-out\s(?P<external_out>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} external-out {{ external_out }}", + "compval": "passive", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "external_out": "{{ external_out }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.mtu_ignore", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smtu-ignore\s(?P<mtu_ignore>\S+) + $""", + re.VERBOSE, + ), + + "setval": "area {{ area_id }} mtu-ignore {{ mtu_ignore }}", + "compval": "mtu_ignore", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mtu_ignore": "{{ mtu_ignore }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.authentication", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sauthentication(?P<auth>) + (\sdisable(?P<disable>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_area_authentication, + "compval": "authentication", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.authentication.ipsec", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sauthentication(?P<auth_key>) + \sipsec(?P<ipsec>) + \sspi\s(?P<spi>\d+) + (\s(?P<algo_type>\S+))? + (\spassword\s(?P<password_key>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_area_authentication_ipsec, + "compval": "authentication.ipsec", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "ipsec": { + "spi": "{{ spi }}", + "algorithim_type": "{{ algo_type }}", + "clear_key": "{{ clear_key }}", + "password_key": "{{ password_key }}", + "key": "{{ key }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.mpls_traffic_eng", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smpls(?P<mpls>) + \straffic-end(?P<traffic_eng>) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} mpls traffic-eng", + "compval": "mpls_traffic_eng", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mpls": { + "traffic_eng": "{{ True if traffic_eng is defined }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.mpls_ldp", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \smpls(?P<mpls>) + (\sauto-config(?P<auto_config>))? + (\ssync(?P<sync>))? + (\ssync-igp-shortcuts(?P<syn_igp_shortcuts>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_mpls_ldp, + "compval": "mpls_ldp", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "mpls": { + "ldp": { + "auto_config": "{{ True if auto_config is defined }}", + "sync": "{{ True if sync is defined }}", + "sync_igp_shortcuts": "{{ True if sync_igp_shortcuts is defined }}", + + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.bfd.minimum_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sbfd(?P<bfd>) + \sminimum-interval\s(?P<minimum_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_area_bfd_minimum_interval, + "compval": "bfd.minimum_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "bfd": { + "minimum_interval": "{{ minimum_interval|int }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.bfd.multiplier", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sbfd(?P<bfd>) + \smultiplier\s(?P<multiplier>\d+) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_area_bfd_multiplier, + "compval": "bfd.multiplier", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "bfd": { + "multiplier": "{{ multiplier|int }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.bfd.fast_detect", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sbfd(?P<bfd>) + \sarea(?P<area_id>) + \sfast-detect(?P<fast_detect>) + (\s(?P<disable>disable))? + (\s(?P<strict_mode>strict-mode))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospfv3_area_bfd_fast_detect, + "compval": "bfd.fast_detect", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "bfd": { + "fast_detect": { + "set": "{{ True if disable is undefined and strict_mode is undefined }}", + "strict_mode": "{{ True if strict_mode is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.stub", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \sstub(?P<nssa>) + (\sno-summary(?P<no_sum>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_stub, + "compval": "stub", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "stub": { + "set": "{{ True if stub is defined and no_summary is undefined }}", + "no_summary": "{{ True if no_summary is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + (\sno-redistribution(?P<no_redis>))? + (\sno-summary(?P<no_sum>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa, + "compval": "nssa", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "nssa": { + "set": "{{ True if nssa is defined and no_summary is undefined and no_redis is undefined }}", + "no_summary": "{{ True if no_summary is defined }}", + "no_redistribution": "{{ True if no_redis is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa.default_information_originate", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + (\sno-redistribution(?P<no_redis>))? + (\sdefault-information-originate(?P<def_info_origin>))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa_def_info_origin, + "compval": "nssa.default_information_originate", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "nssa": { + "default_information_originate": { + "metric": "{{ metric|int }}", + "metric_type": "{{ metric_type|int }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "area.ranges", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \srange(?P<range>) + \s(?P<address>\S+) + (\sadvertise(?P<advertise>)) + (\snot-advertise(?P<not_advertise>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_ranges, + "compval": "ranges", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "ranges": [ + { + "address": "{{ address }}", + "advertise": "{{ True if advertise is defined }}", + "not_advertise": "{{ True if not_advertise is defined }}", + }, + ], + }, + }, + }, + }, + }, + }, + { + "name": "area.nssa.translate", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \snssa(?P<nssa>) + \stranslate(?P<translate>) + \stype7(?P<type7>) + \salways\s(?P<always>) + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_nssa_translate, + "compval": "nssa.translate", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "area_id": "{{ area_id }}", + "nssa": { + "translate": { + "type7": { + "always": "{{ True if always is defined }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.hello_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \shello-interval\s(?P<hello_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} hello-interval {{ hello_interval }}", + "compval": "hello_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": + { + "id": "{{ id }}", + "hello_interval": "{{ hello_interval|int }}", + }, + + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.dead_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sdead-interval\s(?P<dead_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} dead-interval {{ dead_interval }}", + "compval": "dead_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "id": "{{ id }}", + "dead_interval": "{{ dead_interval|int }}", + }, + + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.retransmit_interval", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sretransmit-interval\s(?P<retransmit_interval>\d+) + $""", + re.VERBOSE, + ), + "setval": "area {{ area_id }} virtual-link {{ id }} retransmit-interval {{ retransmit_interval }}", + "compval": "retransmit_interval", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "id": "{{ id }}", + "retransmit_interval": "{{ retransmit_interval|int }}", + }, + }, + + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \savirtual-link\s(?P<id>\S+) + \sauthentication(?P<auth>) + (\skeychain\s(?P<keychain>\S+))? + (\snull(?P<no_auth>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication, + "compval": "authentication", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "authentication": { + "no_auth": "{{ True if no_auth is defined }}", + "keychain": "{{ keychain }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication_key", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sauthentication-key(?P<auth_key>) + (\s(?P<password>\S+))? + (\sclear\s(?P<clear>)\S+)? + (\sencrypted(?P<encrypted>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication_key, + "compval": "authentication_key", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "authentication_key": { + "clear": "{{ clear }}", + "encrypted": "{{ encrypted}}", + "password": "{{ password if clear is undefined and encrypted is undefined }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "virtual_link.authentication.message_digest", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sarea\s(?P<area_id>\S+) + \svirtual-link\s(?P<id>\S+) + \sauthentication(?P<auth>) + \smessage-digest(?P<md>) + \skeychain(?P<md_key>\s\S+) + *$""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_area_vlink_authentication_md, + "compval": "authentication.message_digest", + "result": { + "processes": { + "{{ pid }}": { + "areas": { + "{{ area_id }}": { + "area_id": "{{ area_id }}", + "virtual_link": { + "{{ id }}": { + "authentication": { + "message_digest": { + "keychain": "{{ md_key }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "link_down_fast_detect", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \slink-down + \sfast-detect(?P<fast_detect>) + $""", + re.VERBOSE, + ), + "setval": "link-down fast-detect", + "result": { + "processes": { + "{{ pid }}": { + "link_down_fast_detect": "{{ True if fast_detect is defined }}", + }, + }, + }, + }, + { + "name": "nsr", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \snsr + \sdisable(?P<disable>) + $""", + re.VERBOSE, + ), + "setval": "nsr disable", + "result": { + "processes": { + "{{ pid }}": { + "disable": "{{ True if disable is defined }}", + }, + }, + }, + }, + { + "name": "database_filter", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdatabase-filter + \sall + \sout\s(?P<outing>\S+) + $""", + re.VERBOSE, + ), + + "setval": "database-filter all out {{ outing }}", + "result": { + "processes": { + "{{ pid }}": { + "outing": "{{ outing }}", + }, + }, + }, + }, + { + "name": "distribute_link_state", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdistribute(?P<distribute>) + \slink-state(?P<link_state>) + (\sinstance-id(?P<inst_id>\d+))? + (\sthrottle(?P<throttle>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_adjacency_distribute_bgp_state, + "result": { + "processes": { + "{{ pid }}": { + "distribute_link_list": { + "instance_id": "{{ inst_id|int }}", + "throttle": "{{ throttle }}", + }, + }, + }, + }, + }, + { + "name": "distribute_bgp_ls", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sdistribute(?P<distribute>) + \sbgp-ls(?P<bgp_ls>) + (\sinstance-id(?P<inst_id>\d+))? + (\sthrottle(?P<throttle>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_adjacency_distribute_bgp_state, + "result": { + "processes": { + "{{ pid }}": { + "distribute_bgp_ls": { + "instance_id": "{{ inst_id|int }}", + "throttle": "{{ throttle }}", + }, + }, + }, + }, + }, + { + "name": "log_adjacency", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \slog(?P<security>) + \sadjacency(?P<adjacency>)? + (\schanges(?P<changes>))? + (\sdisable(?P<disable>))? + (\sdetails(?P<details>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_log_adjacency, + "result": { + "processes": { + "{{ pid }}": { + "log_adjacency_changes": { + "set": "{{ True changes id defined and disable is undefined and detail is undefined }}", + "disable": "{{ True if disable is defined }}", + "details": "{{ True if details is defined }}", + }, + }, + }, + }, + }, + { + "name": "max_lsa", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + (\smax-lsa\s(?P<threshold>\d+))? + (\swarning-only\s(?P<warning_only>\d+)? + (\signore-time\s(?P<ignore_time>\d+))? + (\signore-count\s(?P<ignore_count>\d+))? + (\sreset-time\s(?P<reset_time>)\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_log_max_lsa, + "result": { + "processes": { + "{{ pid }}": { + "max_lsa": { + "threshold": "{{ threshold|int }}", + "warning_only": "{{ warning_only|int }}", + "ignore_time": "{{ ignore_time|int }}", + "ignore_count": "{{ ignore_count|int }}", + "reset_time": "{{ reset_time|int }}", + }, + }, + }, + }, + }, + { + "name": "max_metric", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \smax-metric + \s*(?P<router_lsa>) + (\s*external-lsa(?P<external_lsa>))? + (\s(?P<max_metric_value>\d+))? + \s*(?P<include_stub>include-stub)* + \s*(?P<on_startup>on-startup)* + \s*(?P<wait_period>\d+)* + \s*(wait-for\sbgp)* + \s*(?P<bgp_asn>\d+)* + \s*(?P<summary_lsa>summary-lsa)* + \s*(?P<sum_lsa_max_metric_value>\d+)* + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_max_metric, + "remval": "max-metric router-lsa", + "result": { + "processes": { + '{{ "pid" }}': { + "max_metric": { + "router_lsa": { + "set": "{{ True if router_lsa is defined and external_lsa is undefined else None }}", + "external_lsa": { + "set": "{{ True if external_lsa is defined and max_metric_value is undefined else None }}", + "max_metric_value": "{{ max_metric_value }}", + }, + "include_stub": "{{ not not include_stub }}", + "on_startup": { + "set": "{{ True if on_startup is defined and (wait_period and bgp_asn) is undefined else None }}", + "wait_period": "{{ wait_period }}", + "wait_for_bgp_asn": "{{ bgp_asn }}", + }, + "summary_lsa": { + "set": "{{ True if summary_lsa is defined and sum_lsa_max_metric_value is undefined else None }}", + "max_metric_value": "{{ sum_lsa_max_metric_value }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mpls_ldp", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \smpls(?P<mpls>) + (\sauto-config(?P<auto_config>))? + (\ssync(?P<sync>))? + (\ssync-igp-shortcuts(?P<syn_igp_shortcuts>))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_mpls_ldp, + "compval": "mpls_ldp", + "result": { + "processes": { + "{{ pid }}": { + "mpls": { + "ldp": { + "auto_config": "{{ True if auto_config is defined }}", + "sync": "{{ True if sync is defined }}", + "sync_igp_shortcuts": "{{ True if sync_igp_shortcuts is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "microloop_avoidance", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \smicroloop(?P<microloop>) + \savoidance(?P<avoidance>) + (\s(?P<protected>protected))? + (\s(?P<segment_routing>segment-routing))? + (\srib-update-delay\s(?P<rib_update_delay>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_microloop_avoidance, + "compval": "microloop_avoidance", + "result": { + "processes": { + "{{ pid }}": { + "microloop_avoidance": { + "protected": "{{ True if protected is defined }}", + "segment_routing": "{{ True if segment_routing is defined }}", + "rib_update_delay": "{{ rib_update_delay }}", + }, + }, + }, + }, + }, + { + "name": "mpls_traffic_eng", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \smpls(?P<mpls>) + \straffic-end(?P<traffic_eng>) + (\sautoroute-exclude(?P<autoroute>))? + (\sroute-policy(?P<route_policy>\S+))? + (\s(?P<igp_intact>igp_intact))? + (\s(?P<ldp_sync_update>ldp-sync-update))? + (\s(?P<multicast_intact>multicast-intact))? + (\srouter-id\s(?P<router_id>\S+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_ospf_mpls_traffic_eng, + "result": { + "processes": { + "{{ pid }}": { + "mpls": { + "autoroute_exclude": { + "route_policy": "{{ route_policy }}", + }, + "igp_intact": "{{ True if igp_intact is defined }}", + "ldp_sync_update": "{{ True if ldp_sync_update is defined }}", + "multicast_intact": "{{ True if multicast_intact is defined }}", + "router_id": "{{ router_id }}", + }, + }, + }, + }, + }, + { + "name": "prefix_suppression", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sprefix-suppression(?P<prefix_suppression>) + (\s(?P<secondary_address>secondary-address))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_prefix_suppression, + "result": { + "processes": { + "{{ pid }}": { + "prefix_suppression": { + "set": "{{ True if prefix_suppression is defined and secondary_address is undefined }}", + "secondary_address": "{{ True if secondary_address is defined }}", + }, + }, + }, + }, + }, + { + "name": "protocol_shutdown", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \sprotocol-shutdown(?P<protocol_shutdown>) + (\s(?P<host_mode>host-mode))? + (\s(?P<on_reload>on-reload))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_protocol_shutdown, + "result": { + "processes": { + "{{ pid }}": { + "protocol_shutdown": { + "set": "{{ True if protocol_shutdown is defined and host_mode is undefined and on_reload is undefined }}", + "host_mode": "{{ True if host_mode is defined }}", + "on_reload": "{{ True if on_reload is defined }}", + }, + }, + }, + }, + }, + { + "name": "timers.lsa", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \slsa + (\sgroup-pacing\s(?P<group_pacing>\d+))? + (\smin-arrival\s(?P<min_arrival>\d+))? + (\srefresh\s(?P<refresh>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_timers_lsa, + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "lsa": { + "group_pacing": "{{ group_pacing|int }}", + "min_arrival": "{{ min_arrival|int }}", + "refresh": "{{ refresh|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.graceful_shutdown", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \sgraceful_shutdown + (\sinitial delay\s(?P<initial_delay>\d+))? + (\sretain routes\s(?P<retain_routes>\d+))? + $""", + re.VERBOSE, + ), + "setval": _tmplt_timers_graceful_shutdown, + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "graceful_shutdown": { + "initial_delay": "{{ initial_delay|int }}", + "retain_routes": "{{ retain_routes|int }}", + }, + }, + }, + }, + }, + }, + { + "name": "throttle.spf", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \sthrottle + \sspf + (\s(?P<change_delay>\d+)) + (\s(?P<second_delay>\d+)) + (\s(?P<max_wait>\d+)) + $""", + re.VERBOSE, + ), + "setval": "timers throttle spf {{ throttle.spf.change_delay }} {{ throttle.spf.second_delay }} {{ throttle.spf.max_wait }}", + "compval": "throttle.lsa_all", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "lsa_all": { + "initial_delay": "{{ initial_delay }}", + "min_delay": "{{ min_delay }}", + "max_delay": "{{ max_delay }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "throttle.lsa_all", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \sthrottle + \slsa + \sall + (\s(?P<initial_delay>\d+)) + (\s(?P<min_delay>\d+)) + (\s(?P<max_delay>\d+)) + $""", + re.VERBOSE, + ), + "setval": "timers throttle lsa all {{ throttle.lsa_all.initial_delay }} {{ throttle.lsa_all.min_delay }} {{ throttle.lsa_all.max_delay }}", + "compval": "throttle.lsa_all", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "lsa_all": { + "initial_delay": "{{ initial_delay }}", + "min_delay": "{{ min_delay }}", + "max_delay": "{{ max_delay }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "throttle.fast_reroute", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \sthrottle + \sfast-reroute\s(?P<fast_reroute>\d+) + $""", + re.VERBOSE, + ), + "setval": "timers throttle fast-reroute {{ fast_reroute }}", + "compval": "throttle.fast_reroute", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "throttle": { + "fast_reroute": "{{ fast_reroute }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.pacing_flood", + "getval": re.compile( + r""" + ^router + \sospfv3\s(?P<pid>\S+) + \stimers + \spacing + \sflood\s(?P<pacing_flood>\d+) + $""", + re.VERBOSE, + ), + "setval": "timers pacing flood {{ pacing_flood }}", + "compval": "timers.pacing_flood", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "pacing_flood": "{{ pacing_flood }}", + + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ping.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ping.py new file mode 100644 index 00000000..74703fbe --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/ping.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Ping parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class PingTemplate(NetworkTemplate): + def __init__(self, lines=None): + super(PingTemplate, self).__init__(lines=lines, tmplt=self) + + # fmt: off + PARSERS = [ + { + 'name': 'rate', + 'getval': re.compile( + r''' + ^Success\srate\sis + (\s(?P<pct>\d+))? + (\spercent\s\((?P<rx>\d+)/(?P<tx>\d+)\))? + (,\s+round-trip\smin/avg/max\s=)? + (\s(?P<min>\d+)/(?P<avg>\d+)/(?P<max>\d+))? + (\s+\w+\s*$|.*\s*$)? + ''', re.VERBOSE, + ), + "setval": "ping" + "{{ (' vrf ' + vrf) if vrf is defined else '' }}" + "{{ (' ' + afi|string ) if afi is defined else '' }}" + "{{ (' ' + dest ) if dest is defined else '' }}" + "{{ (' count ' + count|string ) if count is defined else '' }}" + "{{ (' df-bit' ) if df_bit|d(False) else '' }}" + "{{ (' sweep' ) if sweep|d(False) else '' }}" + "{{ (' validate' ) if validate|d(False) else '' }}" + "{{ (' size ' + size|string ) if size is defined else '' }}" + "{{ (' source ' + source) if source is defined else '' }}", + 'result': { + "ping": { + 'loss_percentage': '{{ 100 - pct|int }}%', + 'loss': '{{ 100 - pct|int }}', + 'rx': '{{ rx|int }}', + 'tx': '{{ tx|int }}', + 'rtt': { + 'min': '{{ min }}', + 'avg': '{{ avg }}', + 'max': '{{ max }}', + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/prefix_lists.py new file mode 100644 index 00000000..8dc6ceee --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/prefix_lists.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Prefix_lists parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Prefix_listsTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Prefix_listsTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "prefix_list", + "getval": re.compile( + r""" + (?P<afi>^(ipv4|ipv6)) + \sprefix-list\s(?P<name>\S+) + $""", + re.VERBOSE, + ), + "setval": "{{afi}} prefix-list {{name}}", + "result": { + "{{ afi }}": { + "afi": "{{ afi }}", + "prefix_lists": { + "{{ name }}": { + "name": "{{ name }}", + }, + }, + }, + + }, + "shared": True, + }, + { + "name": "prefix", + "getval": re.compile( + r""" + \s(?P<sequence>\d+) + \s(?P<action>deny|permit) + \s(?P<prefix>\S+) + (\seq\s(?P<eq>\d+))? + (\sge\s(?P<ge>\d+))? + (\sle\s(?P<le>\d+))? + $""", + re.VERBOSE, + ), + "setval": "{{afi}} prefix-list {{name}} {{sequence}} {{action}} {{prefix}}" + "{{ (' eq ' + eq|string) if eq|d('') else '' }}" + "{{ (' ge ' + ge|string) if ge|d('') else '' }}" + "{{ (' le ' + le|string) if le|d('') else '' }}", + "result": { + "{{ afi |d()}}": { + "afi": "{{ afi|d() }}", + "prefix_lists": { + "{{ name|d() }}": { + "name": "{{ name|d()}}", + "entries": [ + { + "sequence": "{{ sequence|d(None) }}", + "action": "{{ action }}", + "prefix": "{{ prefix }}", + "eq": "{{ eq }}", + "ge": "{{ ge }}", + "le": "{{ le }}", + }, + ], + }, + }, + }, + }, + }, + { + "name": "description", + "getval": re.compile( + r""" + \s(?P<sequence>\d+) + \s(?P<action>remark) + \s(?P<desc>\S+) + $""", + re.VERBOSE, + ), + "setval": "{{afi}} prefix-list {{name}} {{sequence}} {{action}} {{description}}", + "result": { + "{{ afi|d() }}": { + "afi": "{{ afi|d() }}", + "prefix_lists": { + "{{ name|d() }}": { + "name": "{{ name|d() }}", + "entries": [ + { + "sequence": "{{ sequence|d(None) }}", + "action": "{{ action }}", + "description": "{{ desc }}", + }, + ], + }, + }, + }, + }, + }, + + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/snmp_server.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/snmp_server.py new file mode 100644 index 00000000..77fe0606 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/rm_templates/snmp_server.py @@ -0,0 +1,3223 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Snmp_server parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +def communities_tmplt(config_data): + name = config_data.get("name", "") + command = "snmp-server community {name}".format(name=name) + if config_data.get("rw"): + command += " RW" + elif config_data.get("ro"): + command += " RO" + if config_data.get("sdrowner"): + command += " SDROwner" + elif config_data.get("systemowner"): + command += " SystemOwner" + if config_data.get("acl_v4"): + command += " IPv4 {IPv4}".format(IPv4=config_data["acl_v4"]) + if config_data.get("acl_v6"): + command += " IPv6 {IPv6}".format(IPv6=config_data["acl_v6"]) + if config_data.get("v4_acl"): + command += " {v4_acl}".format(v4_acl=config_data["v4_acl"]) + return command + + +def community_maps_tmplt(config_data): + name = config_data.get("name", "") + command = "snmp-server community-map {name}".format(name=name) + if config_data.get("context"): + command += " context {context}".format(context=config_data["context"]) + if config_data.get("security_name"): + command += " security-name {security_name}".format( + security_name=config_data["security_name"], + ) + if config_data.get("target_list"): + command += " target-list {target_list}".format( + target_list=config_data["target_list"], + ) + return command + + +def tmplt_correlator_rule(config_data): + rule_name = config_data.get("rule_name") + command = "snmp-server correlator rule {rule_name}".format( + rule_name=rule_name, + ) + if config_data.get("timeout"): + command += " timeout {timeout}".format(timeout=config_data["timeout"]) + return command + + +def group_tmplt(config_data): + group = config_data.get("group", "") + command = "snmp-server group {group}".format(group=group) + if config_data.get("version"): + command += " {version}".format(version=config_data["version"]) + if config_data.get("notify"): + command += " notify {notify}".format(notify=config_data["notify"]) + if config_data.get("read"): + command += " read {read}".format(read=config_data["read"]) + if config_data.get("write"): + command += " write {write}".format(write=config_data["write"]) + if config_data.get("context"): + command += " context {context}".format(context=config_data["context"]) + if config_data.get("acl_v4"): + command += " IPv4 {acl_v4}".format(acl_v4=config_data["acl_v4"]) + if config_data.get("acl_v6"): + command += " IPv6 {acl_v6}".format(acl_v6=config_data["acl_v6"]) + if config_data.get("v4_acl"): + command += " {v4_acl}".format(v4_acl=config_data["v4_acl"]) + return command + + +def host_tmplt(config_data): + host = config_data.get("host", "") + command = "snmp-server host {host}".format(host=host) + if config_data.get("informs"): + command += " informs" + if config_data.get("traps"): + command += " traps" + if config_data.get("version"): + command += " version {version}".format(version=config_data["version"]) + if config_data.get("community"): + command += " {community}".format(community=config_data["community"]) + if config_data.get("udp_port"): + command += " udp-port {udp_port}".format( + udp_port=config_data["udp_port"], + ) + if config_data.get("write"): + command += " write {write}".format(write=config_data["write"]) + return command + + +def interfaces_tmplt(config_data): + interface = config_data.get("name", "") + notification_linkupdown_disable = config_data.get( + "notification_linkupdown_disable", + "", + ) + index_persistent = config_data.get("index_persistent", "") + + cmds = [] + if notification_linkupdown_disable: + command = "snmp-server interface {interface} notification linkupdown disable".format( + interface=interface, + ) + cmds.append(command) + if config_data.get("index_persistent"): + command = "snmp-server snmp-server interface {interface} index persistence".format( + interface=interface, + ) + cmds.append(command) + if not notification_linkupdown_disable and not index_persistent and interface: + command = "snmp-server interface {interface}".format( + interface=interface, + ) + cmds.append(command) + return cmds + + +def mib_schema_tmplt(config_data): + name = config_data.get("name", "") + object_list = config_data.get("object_list", "") + poll_interval = config_data.get("poll_interval", "") + + cmds = [] + if object_list: + command = "snmp-server mib bulkstat schema {name} object-list {object_list}".format( + name=name, + object_list=object_list, + ) + cmds.append(command) + if poll_interval: + command = "snmp-server mib bulkstat schema {name} poll-interval {poll_interval}".format( + name=name, + poll_interval=poll_interval, + ) + cmds.append(command) + if not object_list and not poll_interval and name: + command = "snmp-server mib bulkstat schema {name}".format(name=name) + cmds.append(command) + return cmds + + +def mib_bulkstat_transfer_ids_tmplt(config_data): + name = config_data.get("name", "") + buffer_size = config_data.get("buffer_size", "") + enable = config_data.get("enable", "") + format_schemaASCI = config_data.get("format_schemaASCI", "") + retain = config_data.get("retain", "") + retry = config_data.get("retry", "") + schema = config_data.get("schema", "") + transfer_interval = config_data.get("transfer_interval", "") + + cmds = [] + if buffer_size: + command = "snmp-server mib bulkstat transfer-id {name} buffer-size {buffer_size}".format( + name=name, + buffer_size=buffer_size, + ) + cmds.append(command) + if enable: + command = "snmp-server mib bulkstat transfer-id {name} enable".format( + name=name, + ) + cmds.append(command) + if format_schemaASCI: + command = "snmp-server mib bulkstat transfer-id {name} format schemaASCII".format( + name=name, + ) + cmds.append(command) + if retain: + command = "snmp-server mib bulkstat transfer-id {name} retain {retain}".format( + name=name, + retain=retain, + ) + cmds.append(command) + if retry: + command = "snmp-server mib bulkstat transfer-id {name} retry {retry}".format( + name=name, + retry=retry, + ) + cmds.append(command) + if schema: + command = "snmp-server mib bulkstat transfer-id {name} schema {schema}".format( + name=name, + schema=schema, + ) + cmds.append(command) + if transfer_interval: + command = "snmp-server mib bulkstat transfer-id {name} transfer_interval {transfer_interval}".format( + name=name, + transfer_interval=transfer_interval, + ) + cmds.append(command) + if ( + not any( + [ + buffer_size, + enable, + format_schemaASCI, + retry, + retain, + schema, + transfer_interval, + ], + ) + and name + ): + command = "snmp-server mib bulkstat transfer-id {name}".format( + name=name, + ) + cmds.append(command) + return cmds + + +def overload_control_tmplt(config_data): + config_data = config_data.get("overload_control", {}) + command = "snmp-server overload-control" + if config_data.get("overload_drop_time"): + command += " {overload_drop_time}".format( + overload_drop_time=config_data["overload_drop_time"], + ) + if config_data.get("overload_throttle_rate"): + command += " {overload_throttle_rate}".format( + overload_throttle_rate=config_data["overload_throttle_rate"], + ) + return command + + +def targets_tmplt(config_data): + name = config_data.get("name", "") + command = "" + if name: + command = "snmp-server target list {name}".format(name=name) + if config_data.get("host"): + command += " host {host}".format(host=config_data["host"]) + if config_data.get("vrf"): + command += " vrf {vrf}".format(vrf=config_data["vrf"]) + return command + + +def tmplt_traps_isis(config_data): + isis = config_data.get("traps", {}).get("isis", {}) + command = "snmp-server traps isis" + if isis.get("all"): + command += " all" + else: + if isis.get("adjacency_change"): + command += " adjacency-change" + if isis.get("area_mismatch"): + command += " area-mismatch" + if isis.get("attempt_to_exceed_max_sequence"): + command += " attempt-to-exceed-max-sequence" + if isis.get("authentication_failure"): + command += " authentication-failure" + if isis.get("authentication_type_failure"): + command += " authentication-type-failure" + if isis.get("corrupted_lsp_detected"): + command += " corrupted-lsp-detected" + if isis.get("database_overload"): + command += " database-overload" + if isis.get("id_len_mismatch"): + command += " id-len-mismatch" + if isis.get("lsp_error_detected"): + command += " lsp-error-detected" + if isis.get("lsp_too_large_to_propagate"): + command += " lsp-too-large-to-propagate" + if isis.get("manual_address_drops"): + command += " manual-address-drops" + if isis.get("max_area_addresses_mismatch"): + command += " max-area-addresses-mismatch" + if isis.get("orig_lsp_buff_size_mismatch"): + command += " orig-lsp-buff-size-mismatch" + if isis.get("version_skew"): + command += " version-skew" + if isis.get("own_lsp_purge"): + command += " own-lsp-purge" + if isis.get("rejected_adjacency"): + command += " rejected-adjacency" + if isis.get("protocols_supported_mismatch"): + command += " protocols-supported-mismatch" + if isis.get("sequence_number_skip"): + command += " sequence-number-skip" + return command + + +def user_tmplt(config_data): + user = config_data.get("user", "") + group = config_data.get("group", "") + version = config_data.get("version", "") + command = "snmp-server user {user} {group} {version}".format( + user=user, + group=group, + version=version, + ) + if config_data.get("acl_v4"): + command += " IPv4 {acl_v4}".format(acl_v4=config_data["acl_v4"]) + if config_data.get("acl_v6"): + command += " IPv6 {acl_v6}".format(acl_v6=config_data["acl_v6"]) + if config_data.get("v4_acl"): + command += " {v4_acl}".format(v4_acl=config_data["v4_acl"]) + if config_data.get("SDROwner"): + command += " SDROwner" + elif config_data.get("SystemOwner"): + command += " SystemOwner" + return command + + +class Snmp_serverTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Snmp_serverTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "chassis_id", + "getval": re.compile( + r""" + ^snmp-server + (\s+chassis-id\s(?P<chassis_id>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server chassis-id {{chassis_id}}", + "result": { + "chassis_id": "{{chassis_id}}", + }, + }, + { + "name": "communities", + "getval": re.compile( + r""" + ^snmp-server\scommunity + (\s(?P<name>\S+))? + (\sRW(?P<rw>))? + (\sRO(?P<ro>))? + (\sSDROwner(?P<sdrowner>))? + (\sSystemOwner(?P<systemowner>))? + (\sIPv4\s(?P<ipv4>\S+))? + (\sIPv6\s(?P<ipv6>\S+))? + (\s(?P<v4acl>\S+))? + $""", re.VERBOSE, + ), + "setval": communities_tmplt, + "result": { + "communities": [ + { + "name": "{{ name }}", + "rw": "{{ True if rw is defined }}", + "ro": "{{ True if ro is defined }}", + "acl_v4": "{{ipv4}}", + "acl_v6": "{{ipv6}}", + "sdrowner": "{{True if sdrowner is defined}}", + "systemowner": "{{True if systemowner is defined }}", + "v4_acl": "{{v4acl}}", + }, + ], + }, + }, + { + "name": "community_maps", + "getval": re.compile( + r""" + ^snmp-server\scommunity-map + (\s(?P<name>\S+))? + (\scontext\s(?P<context>\S+))? + (\ssecurity-name\s(?P<security_name>\S+))? + (\starget-list\s(?P<target_list>\S+))? + $""", re.VERBOSE, + ), + "setval": community_maps_tmplt, + "result": { + "community_maps": [ + { + "name": "{{ name }}", + "context": "{{context}}", + "security_name": "{{security_name}}", + "target_list": "{{target_list}}", + }, + ], + }, + }, + { + "name": "correlator.buffer_size", + "getval": re.compile( + r""" + ^snmp-server\scorrelator + (\sbuffer-size\s(?P<buffer_size>\S+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server correlator buffer-size {{correlator.buffer_size }}", + "result": { + "correlator": { + "buffer_size": "{{ buffer_size }}", + }, + }, + }, + { + "name": "correlator.rules", + "getval": re.compile( + r""" + ^snmp-server\scorrelator + (\srule\s(?P<name>\S+))? + (\s+timeout\s(?P<timeout>\S+))? + $""", re.VERBOSE, + ), + "setval": tmplt_correlator_rule, + "result": { + "correlator": { + "rules": [ + { + "rule_name": "{{ name }}", + "timeout": "{{ timeout }}", + + }, + ], + }, + }, + }, + { + "name": "correlator.rule_sets", + "getval": re.compile( + r""" + ^snmp-server\scorrelator\sruleset\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "snmp-server correlator ruleset {{name}}", + "result": { + "correlator": { + "rule_sets": + [ + {"name": "{{ name }}"}, + ], + }, + }, + }, + { + "name": "contact", + "getval": re.compile( + r""" + ^snmp-server\scontact\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "snmp-server contact {{contact}}", + "result": { + "contact": "{{name}}", + }, + }, + { + "name": "context", + "getval": re.compile( + r""" + ^snmp-server\scontext\s(?P<name>\S+) + $""", re.VERBOSE, + ), + "setval": "snmp-server context {{name}}", + "result": { + "context": { + "{{name}}": "{{name}}", + }, + }, + }, + { + "name": "drop.report_IPv4", + "getval": re.compile( + r""" + ^snmp-server\sdrop + (\sreport\sacl\sIPv4\s(?P<report_IPv4>\S+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server drop report acl IPv4 {{drop.report_IPv4}}", + "result": { + "drop": { + "report_IPv4": "{{report_IPv4}}", + }, + }, + }, + { + "name": "drop.report_IPv6", + "getval": re.compile( + r""" + ^snmp-server\sdrop + (\sreport\sacl\sIPv6\s(?P<report_IPv6>\S+)) + + $""", re.VERBOSE, + ), + "setval": "snmp-server drop report acl IPv6 {{drop.report_IPv6}}", + "result": { + "drop": { + "report_IPv6": "{{report_IPv6}}", + }, + }, + }, + { + "name": "drop.unknown_user", + "getval": re.compile( + r""" + ^snmp-server\sdrop + (\sunknown-user(?P<unknown_user>)) + + $""", re.VERBOSE, + ), + "setval": "snmp-server drop unknown-user", + "result": { + "drop": { + "unknown_user": "{{True if unknown_user is defined}}", + }, + }, + }, + { + "name": "groups", + "getval": re.compile( + r""" + ^snmp-server + (\sgroup\s(?P<group>\S+)) + (\s(?P<version>v1|v2c|v3)) + (\snotify\s(?P<notify>\S+))? + (\sread\s(?P<read>\S+))? + (\swrite\s(?P<write>\S+))? + (\scontext\s(?P<context>\S+))? + (\sIPv4\s(?P<IPv4>\S+))? + (\sIPv6\s(?P<IPv6>\S+))? + (\s(?P<v4acl>\S+))? + $""", re.VERBOSE, + ), + "setval": group_tmplt, + "result": { + "groups": [ + { + "group": "{{ group }}", + "acl_v4": "{{IPv4}}", + "acl_v6": "{{IPv6}}", + "context": "{{context}}", + "notify": "{{notify}}", + "read": "{{read}}", + "write": "{{write}}", + "v4_acl": "{{v4acl}}", + "version": "{{version}}", + }, + ], + }, + }, + { + "name": "hosts", + "getval": re.compile( + r""" + ^snmp-server(\shost\s(?P<host>\S+)) + (\s(?P<traps>traps))? + (\s(?P<informs>informs))? + (\sversion\s(?P<version>1|2c|3))? + (\s(?P<community>\S+))? + (\sudp-port\s(?P<port>\d+))? + $""", re.VERBOSE, + ), + "setval": host_tmplt, + "result": { + "hosts": [ + { + "host": "{{ host }}", + "traps": "{{True if traps is defined}}", + "informs": "{{True if informs is defined}}", + "community": "{{community}}", + "udp_port": "{{port}}", + "version": "{{version}}", + }, + ], + }, + }, + { + "name": "ifindex", + "getval": re.compile( + r""" + ^snmp-server(\sifindex\spersist(?P<ifindex>)) + $""", re.VERBOSE, + ), + "setval": "snmp-server ifindex persist", + "result": { + "ifindex": "{{True if ifindex is defined}}", + }, + }, + { + "name": "ifmib.internal_cache_max_duration", + "getval": re.compile( + r""" + ^snmp-server\sifmib + (\sinternal\scache\smax-duration\s(?P<cache>\S+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server ifmib internal cache max-duration {{ifmib.internal_cache_max_duration}}", + "result": { + "ifmib": { + "internal_cache_max_duration": "{{cache}}", + }, + }, + }, + { + "name": "ifmib.ipsubscriber", + "getval": re.compile( + r""" + ^snmp-server\sifmib + (\sipsubscriber(?P<ipsub>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server ifmib ipsubscriber", + "result": { + "ifmib": { + "internal_cache_max_duration": "{{cache}}", + "ipsubscriber": "{{True if ipsub is defined}}", + "stats": "{{True if s_cache is defined}}", + "ifalias_long": "{{True if long is defined}}", + }, + }, + }, + { + "name": "ifmib.stats", + "getval": re.compile( + r""" + ^snmp-server\sifmib + (\sstats\scache(?P<s_cache>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server ifmib stats cache", + "result": { + "ifmib": { + "stats": "{{True if s_cache is defined}}", + }, + }, + }, + { + "name": "ifmib.ifalias_long", + "getval": re.compile( + r""" + ^snmp-server\sifmib + (\sifalias\slong(?P<long>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server ifmib ifalias long", + "result": { + "ifmib": { + "ifalias_long": "{{True if long is defined}}", + }, + }, + }, + { + "name": "inform.pending", + "getval": re.compile( + r""" + ^snmp-server\sinform + (\spending\s(?P<pending>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server inform pending {{inform.pending}}", + "result": { + "inform": { + "pending": "{{pending}}", + + }, + }, + }, + { + "name": "inform.retries", + "getval": re.compile( + r""" + ^snmp-server\sinform + (\sretries\s(?P<retries>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server inform retries {{inform.retries}}", + "result": { + "inform": { + "retries": "{{retries}}", + }, + }, + }, + { + "name": "inform.timeout", + "getval": re.compile( + r""" + ^snmp-server\sinform + (\stimeout\s(?P<timeout>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server inform pending {{inform.timeout}}", + "result": { + "inform": { + "timeout": "{{timeout}}", + + }, + }, + }, + { + "name": "interfaces", + "getval": re.compile( + r""" + ^snmp-server(\sinterface\s(?P<interface>\S+)) + (\snotification\slinkupdown\sdisable(?P<notification_linkupdown_disable>))? + (\sndex\spersistence(?P<index_persistent>))? + $""", re.VERBOSE, + ), + "setval": interfaces_tmplt, + "result": { + "interfaces": { + "{{interface}}": { + "name": "{{ interface }}", + "notification_linkupdown_disable": "{{True if notification_linkupdown_disable is defined}}", + "index_persistent": "{{True if index_persistent is defined}}", + }, + }, + }, + }, + { + "name": "ipv4.dscp", + "getval": re.compile( + r""" + ^snmp-server + \sipv4\sdscp\s(?P<dscp>\S+) + $""", re.VERBOSE, + ), + "setval": "snmp-server ipv4 dscp {{ipv4.dscp}}", + "result": { + "ipv4": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv6.dscp", + "getval": re.compile( + r""" + ^snmp-server + (\sipv6\sdscp\s(?P<dscp>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server ipv6 dscp {{ipv6.dscp}}", + "result": { + "ipv6": { + "dscp": "{{dscp}}", + }, + }, + }, + { + "name": "ipv4.precedence", + "getval": re.compile( + r""" + ^snmp-server + (\sipv4\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server ipv4 precedence {{ipv4.precedence}}", + "result": { + "ipv4": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "ipv6.precedence", + "getval": re.compile( + r""" + ^snmp-server + (\sipv6\sprecedence\s(?P<precedence>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server ipv6 precedence {{ipv6.precedence}}", + "result": { + "ipv6": {"precedence": "{{precedence}}"}, + }, + }, + { + "name": "location", + "getval": re.compile( + r""" + ^snmp-server(\slocation\s(?P<loc>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server location {{location}}", + "result": { + "location": "{{ loc }}", + }, + }, + { + "name": "logging_threshold_oid_processing", + "getval": re.compile( + r""" + ^snmp-server(\slogging\sthreshold\soid-processing\s(?P<loc>\d+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server logging threshold oid-processing {{logging_threshold_oid_processing}}", + "result": { + "logging_threshold_oid_processing": "{{ loc }}", + }, + }, + { + "name": "logging_threshold_pdu_processing", + "getval": re.compile( + r""" + ^snmp-server(\slogging\sthreshold\spdu-processing\s(?P<loc>\d+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server logging threshold pdu-processing {{logging_threshold_pdu_processing}}", + "result": { + "logging_threshold_pdu_processing": "{{ loc }}", + }, + }, + { + "name": "mib_bulkstat_max_procmem_size", + "getval": re.compile( + r""" + ^snmp-server(\smib\sbulkstat\smax-procmem-size\s(?P<loc>\d+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server mib bulkstat max-procmem-size {{mib_bulkstat_max_procmem_size}}", + "result": { + "mib_bulkstat_max_procmem_size": "{{ loc }}", + }, + }, + { + "name": "mib_object_lists", + "getval": re.compile( + r""" + ^snmp-server(\smib\sbulkstat\sobject-list\s(?P<o_list>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server mib bulkstat object-list {{mib_object}}", + "result": { + "mib_object_lists": { + "{{o_list}}": "{{o_list}}", + }, + }, + }, + { + "name": "mib_schema", + "getval": re.compile( + r""" + ^snmp-server(\smib\sbulkstat\sschema\s(?P<mib>\S+)) + (\sobject-list\s(?P<o_list>\S+))? + (\spoll-interval\s(?P<p_interval>\S+))? + $""", re.VERBOSE, + ), + "setval": mib_schema_tmplt, + "result": { + "mib_schema": { + "{{mib}}": { + "name": "{{ mib }}", + "poll_interval": "{{p_interval}}", + "object_list": "{{o_list}}", + }, + }, + }, + }, + { + "name": "mib_bulkstat_transfer_ids", + "getval": re.compile( + r""" + ^snmp-server(\smib\sbulkstat\stransfer-id\s(?P<mib1>\S+)) + (\sretry\s(?P<retry>\S+))? + (\sbuffer-size\s(?P<buffer_size>\S+))? + (\senable(?P<enable>))? + (\sformat\sschemaASCII(?P<format>))? + (\sretain\s(?P<retain>\S+))? + (\sschema\s(?P<schema>\S+))? + (\stransfer-interval\s(?P<ti>\S+))? + + $""", re.VERBOSE, + ), + "setval": mib_bulkstat_transfer_ids_tmplt, + "result": { + "mib_bulkstat_transfer_ids": { + "{{mib1}}": { + "name": "{{ mib1 }}", + "buffer_size": "{{buffer_size}}", + "enable": "{{True if enable is defined}}", + "format_schemaASCI": "{{True if format is defined}}", + "retain": "{{retain}}", + "schema": "{{schema}}", + "retry": "{{retry}}", + "transfer_interval": "{{ti}}", + }, + }, + }, + }, + { + "name": "mroutemib_send_all_vrf", + "getval": re.compile( + r""" + ^snmp-server(\smroutemib\ssend-all-vrf(?P<send>)) + $""", re.VERBOSE, + ), + "setval": "snmp-server mroutemib send-all-vrf", + "result": { + "mroutemib_send_all_vrf": "{{ True if send is defined }}", + }, + }, + { + "name": "notification_log_mib.size", + "getval": re.compile( + r""" + ^snmp-server\snotification-log-mib + (\ssize\s(?P<size>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server notification-log-mib size {{notification_log_mib.size}}", + "result": { + "notification_log_mib": { + "size": "{{size}}", + }, + }, + }, + { + "name": "notification_log_mib.default", + "getval": re.compile( + r""" + ^snmp-server\snotification-log-mib + (\sdefault(?P<default>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server notification-log-mib default", + "result": { + "notification_log_mib": { + "default": "{{True if default is defined}}", + }, + }, + }, + { + "name": "notification_log_mib.disable", + "getval": re.compile( + r""" + ^snmp-server\snotification-log-mib + (\sdisable(?P<disable>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server notification-log-mib disable", + "result": { + "notification_log_mib": { + "disable": "{{True if disable is defined}}", + }, + }, + }, + { + "name": "notification_log_mib.GlobalSize", + "getval": re.compile( + r""" + ^snmp-server\snotification-log-mib + (\sGlobalSize\s(?P<gsize>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server notification-log-mib GlobalSize {{notification_log_mib.GlobalSize}}", + "result": { + "notification_log_mib": { + "GlobalSize": "{{gsize}}", + + }, + }, + }, + { + "name": "oid_poll_stats", + "getval": re.compile( + r""" + ^snmp-server(\soid-poll-stats(?P<oid_stats>)) + $""", re.VERBOSE, + ), + "setval": "snmp-server oid-poll-stats", + "result": { + "oid_poll_stats": "{{ True if oid_stats is defined }}", + }, + }, + { + "name": "overload_control", + "getval": re.compile( + r""" + ^snmp-server\soverload-control + (\s(?P<overload_drop_time>\d+))? + (\s(?P<overload_throttle_rate>\d+))? + $""", re.VERBOSE, + ), + "setval": overload_control_tmplt, + "result": { + "overload_control": { + "overload_drop_time": "{{overload_drop_time}}", + "overload_throttle_rate": "{{overload_throttle_rate}}", + }, + }, + }, + { + "name": "packetsize", + "getval": re.compile( + r""" + ^snmp-server(\spacketsize\s(?P<packetsize>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server packetsize {{packetsize}}", + "result": { + "packetsize": "{{ packetsize }}", + }, + }, + { + "name": "queue_length", + "getval": re.compile( + r""" + ^snmp-server(\squeue-length\s(?P<queue_length>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server queue-length {{queue_length}}", + "result": { + "queue_length": "{{ queue_length }}", + }, + }, + { + "name": "targets", + "getval": re.compile( + r""" + ^snmp-server(\starget\slist\s(?P<targets>\S+)) + (\shost\s(?P<host>\S+))? + (\svrf\s(?P<vrf>\S+))? + $""", re.VERBOSE, + ), + "setval": targets_tmplt, + "result": { + "targets": [ + { + "name": "{{ targets }}", + "host": "{{host}}", + "vrf": "{{vrf}}", + }, + ], + }, + }, + { + "name": "throttle_time", + "getval": re.compile( + r""" + ^snmp-server(\sthrottle-time\s(?P<throttle_time>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server throttle-time {{throttle_time}}", + "result": { + "throttle_time": "{{ throttle_time }}", + }, + }, + { + "name": "timeouts.duplicate", + "getval": re.compile( + r""" + ^snmp-server\stimeouts + (\sduplicate\s(?P<duplicate>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server timeouts duplicate {{timeouts.duplicate}}", + "result": { + "timeouts": { + "duplicate": "{{duplicate}}", + }, + }, + }, + { + "name": "timeouts.inQdrop", + "getval": re.compile( + r""" + ^snmp-server\stimeouts + (\sinQdrop\s(?P<inQdrop>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server timeouts inQdrop {{timeouts.inQdrop}}", + "result": { + "timeouts": { + "inQdrop": "{{inQdrop}}", + }, + }, + }, + { + "name": "timeouts.subagent", + "getval": re.compile( + r""" + ^snmp-server\stimeouts + (\ssubagent\s(?P<subagent>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server timeouts subagent {{timeouts.subagent}}", + "result": { + "timeouts": { + "subagent": "{{subagent}}", + + }, + }, + }, + { + "name": "timeouts.pdu_stats", + "getval": re.compile( + r""" + ^snmp-server\stimeouts + (\spdu\sstats\s(?P<pdu>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server timeouts pdu stats {{timeouts.pdu_stats}}", + "result": { + "timeouts": { + "pdu_stats": "{{pdu}}", + + }, + }, + }, + { + "name": "timeouts.threshold", + "getval": re.compile( + r""" + ^snmp-server\stimeouts + (\sthreshold\s(?P<threshold>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server timeouts threshold {{timeouts.threshold}}", + "result": { + "timeouts": { + "threshold": "{{threshold}}", + }, + }, + }, + { + "name": "trap.throttle_time", + "getval": re.compile( + r""" + ^snmp-server\strap + (\sthrottle-time\s(?P<throttle_time>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server trap throttle-time {{trap.throttle_time}}", + "result": { + "trap": { + "throttle_time": "{{throttle_time}}", + + }, + }, + }, + { + "name": "trap.authentication_vrf_disable", + "getval": re.compile( + r""" + ^snmp-server\strap + (\sauthentication\svrf\sdisable(?P<authentication_vrf_disable>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server trap authentication vrf disable", + "result": { + "trap": { + "authentication_vrf_disable": "{{True if authentication_vrf_disable is defined}}", + }, + }, + }, + { + "name": "trap.link_ietf", + "getval": re.compile( + r""" + ^snmp-server\strap + (\slink\sietf(?P<link_ietf>))? + (\sthrottle-time\s(?P<throttle_time>\d+))? + $""", re.VERBOSE, + ), + "setval": "snmp-server trap link ietf", + "result": { + "trap": { + "link_ietf": "{{True if link_ietf is defined}}", + }, + }, + }, + { + "name": "trap_source", + "getval": re.compile( + r""" + ^snmp-server(\strap-source\s(?P<trap_source>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server trap-source {{trap_source}}", + "result": { + "trap_source": "{{ trap_source }}", + }, + }, + { + "name": "trap_timeout", + "getval": re.compile( + r""" + ^snmp-server(\strap-timeout\s(?P<trap_timeout>\S+)) + $""", re.VERBOSE, + ), + "setval": "snmp-server trap-timeout {{trap_timeout}}", + "result": { + "trap_timeout": "{{ trap_timeout }}", + }, + }, + { + "name": "traps.addrpool.low", + "getval": re.compile( + r""" + ^snmp-server\straps + (\saddrpool\slow(?P<addrpool_low>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps addrpool low", + "result": { + "traps": { + "addrpool": { + "low": "{{True if addrpool_low is defined}}", + }, + }, + + }, + }, + { + "name": "traps.addrpool.high", + "getval": re.compile( + r""" + ^snmp-server\straps + (\saddrpool\shigh(?P<addrpool_high>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps addrpool high", + "result": { + "traps": { + "addrpool": { + "high": "{{True if addrpool_high is defined}}", + }, + }, + + }, + }, + { + "name": "traps.bfd", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sbfd(?P<bfd>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bfd", + "result": { + "traps": { + "bfd": "{{True if bfd is defined}}", + }, + }, + }, + { + "name": "traps.bgp.cbgp2", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sbgp\scbgp2(?P<bgp_cgp2>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bgp cbgp2", + "result": { + "traps": { + + "bgp": { + "cbgp2": "{{True if bgp_cgp2 is defined}}", + }, + }, + }, + }, + { + "name": "traps.bgp.updown", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sbgp\supdown(?P<bgp_updown>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bgp updown", + "result": { + "traps": { + "bgp": { + "updown": "{{True if updown is defined}}", + }, + }, + }, + }, + { + "name": "traps.bulkstat_collection", + "getval": re.compile( + r""" + ^snmp-server\straps + + (\sbulkstat\scollection(?P<bulkstat_collection>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bulkstat collection", + "result": { + "traps": { + + "bulkstat_collection": "{{True if bulkstat_collection is defined}}", + + }, + }, + }, + { + "name": "traps.bulkstat_transfer", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sbulkstat\stransfer(?P<bulkstat_t>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bulkstat transfer", + "result": { + "traps": { + + "bulkstat_transfer": "{{True if bulkstat_t is defined}}", + + }, + }, + }, + { + "name": "traps.bridgemib", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sbridgemib(?P<bridgemib>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps bridgemib", + "result": { + "traps": { + + "bridgemib": "{{True if bridgemib is defined}}", + + }, + }, + }, + { + "name": "traps.copy_complete", + "getval": re.compile( + r""" + ^snmp-server\straps + (\scopy-complete(?P<copy_complete>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps copy-complete", + "result": { + "traps": { + + "copy_complete": "{{True if copy_complete is defined}}", + + }, + }, + }, + { + "name": "traps.cisco_entity_ext", + "getval": re.compile( + r""" + ^snmp-server\straps + (\scisco-entity-ext(?P<cee>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps cisco-entity-ext", + "result": { + "traps": { + + "cisco_entity_ext": "{{True if cee is defined}}", + + }, + }, + }, + { + "name": "traps.config", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sconfig(?P<config>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps config", + "result": { + "traps": { + + "config": "{{True if config is defined}}", + + }, + }, + }, + { + "name": "traps.diameter.peerdown", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sdiameter\speerdown(?P<peerdown>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps diameter peerdown", + "result": { + "traps": { + "diameter": { + "peerdown": "{{True if peerdown is defined}}", + }, + + }, + }, + }, + { + "name": "traps.diameter.peerup", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sdiameter\speerup(?P<peerup>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps diameter peerup", + "result": { + "traps": { + "diameter": { + "peerup": "{{True if peerup is defined}}", + }, + + }, + }, + }, + { + "name": "traps.diameter.protocolerror", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sdiameter\sprotocolerror(?P<protocolerror>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps diameter protocolerror", + "result": { + "traps": { + "diameter": { + "protocolerror": "{{True if protocolerror is defined}}", + }, + + }, + }, + }, + { + "name": "traps.diameter.permanentfail", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sdiameter\spermanentfail(?P<permanentfail>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps diameter permanentfail", + "result": { + "traps": { + "diameter": { + "permanentfail": "{{True if permanentfail is defined}}", + }, + + }, + }, + }, + { + "name": "traps.diameter.transientfail", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sdiameter\stransientfail(?P<transientfail>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps diameter transientfail", + "result": { + "traps": { + "diameter": { + "transientfail": "{{True if transientfail is defined}}", + }, + + }, + }, + }, + { + "name": "traps.entity", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity(?P<entity>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity", + "result": { + "traps": { + "entity": "{{True if entity is defined}}", + }, + }, + }, + { + "name": "traps.entity_redundancy.all", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity-redundancy\sall(?P<all>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity-redundancy all", + "result": { + "traps": { + "entity_redundancy": { + "all": "{{True if all is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.entity_redundancy.status", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity-redundancy\sstatus(?P<status>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity-redundancy status", + "result": { + "traps": { + "entity_redundancy": { + "status": "{{True if status is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.entity_redundancy.switchover", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity-redundancy\sswitchover(?P<switchover>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity-redundancy switchover", + "result": { + "traps": { + "entity_redundancy": { + "switchover": "{{True if switchover is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.entity_state.operstatus", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity-state\soperstatus(?P<operstatus>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity-state operstatus", + "result": { + "traps": { + "entity_state": { + "operstatus": "{{True if operstatus is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.entity_state.switchover", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sentity-state\sswitchover(?P<switchover>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps entity-state switchover", + "result": { + "traps": { + "entity_state": { + "switchover": "{{True if switchover is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.flash.insertion", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sflash\sinsertion(?P<f_insertion>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps flash insertion", + "result": { + "traps": { + "flash": { + "insertion": "{{True if f_insertion is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.flash.removal", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sflash\sremoval(?P<f_removal>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps flash removal", + "result": { + "traps": { + "flash": { + "removal": "{{True if f_removal is defined }}", + + }, + + }, + }, + }, + { + "name": "traps.fru_ctrl", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sfru-ctrl(?P<fru_ctrl>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps fru-ctrl", + "result": { + "traps": { + "fru_ctrl": "{{True if fru_ctrl is defined }}", + }, + }, + }, + { + "name": "traps.hsrp", + "getval": re.compile( + r""" + ^snmp-server\straps + (\shsrp(?P<hsrp>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps hsrp", + "result": { + "traps": { + "hsrp": "{{True if hsrp is defined }}", + }, + }, + }, + { + "name": "traps.ipsla", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sipsla(?P<ipsla>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ipsla", + "result": { + "traps": { + "ipsla": "{{True if ipsla is defined }}", + }, + }, + }, + { + "name": "traps.ipsec.start", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sipsec\stunnel\sstart(?P<ipsec_start>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ipsec tunnel start", + "result": { + "traps": { + "ipsec": { + "start": "{{True if ipsec_start is defined}}", + }, + }, + }, + }, + { + "name": "traps.ipsec.stop", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sipsec\stunnel\sstop(?P<ipsec_stop>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ipsec tunnel stop", + "result": { + "traps": { + "ipsec": { + "stop": "{{True if ipsec_stop is defined}}", + }, + }, + }, + }, + { + "name": "traps.isakmp.start", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sisakmp\stunnel\sstart(?P<isakmp_start>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps isakmp tunnel start", + "result": { + "traps": { + "isakmp": { + "start": "{{True if isakmp_start is defined}}", + }, + + }, + }, + }, + { + "name": "traps.isakmp.stop", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sisakmp\stunnel\sstop(?P<isakmp_stop>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps isakmp tunnel stop", + "result": { + "traps": { + "isakmp": { + "stop": "{{True if isakmp_stop is defined}}", + }, + }, + }, + }, + { + "name": "traps.isis", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sisis\sall(?P<isis_all>))? + (\sisis(\sdatabase-overload(?P<database_overload>))?(\smanual-address-drops(?P<manual_address_drops>))? + (\scorrupted-lsp-detected(?P<corrupted_lsp_detected>))? + (\sattempt-to-exceed-max-sequence(?P<attempt_to_exceed_max_sequence>))? + (\sid-len-mismatch(?P<id_len_mismatch>))? + (\smax-area-addresses-mismatch(?P<max_area_addresses_mismatch>))? + (\sown-lsp-purge(?P<own_lsp_purge>))? + (\ssequence-number-skip(?P<sequence_number_skip>))? + (\sauthentication-type-failure(?P<authentication_type_failure>))? + (\sauthentication-failure(?P<authentication_failure>))? + (\sversion-skew(?P<version_skew>))? + (\sarea-mismatch(?P<area_mismatch>))? + (\srejected-adjacency(?P<rejected_adjacency>))? + (\slsp-too-large-to-propagate(?P<lsp_too_large_to_propagate>))? + (\sorig-lsp-buff-size-mismatch(?P<orig_lsp_buff_size_mismatch>))? + (\sprotocols-supported-mismatch(?P<protocols_supported_mismatch>))? + (\sadjacency-change(?P<adjacency_change>))? + (\slsp-error-detected(?P<lsp_error_detected>))?)? + $""", re.VERBOSE, + ), + "setval": tmplt_traps_isis, + "result": { + "traps": { + + "isis": { + "all": "{{True if isis_all is defined}}", + "id_len_mismatch": "{{True if id_len_mismatch is defined}}", + "database_overload": "{{True if database_overload is defined}}", + "manual_address_drops": "{{True if manual_address_drops is defined}}", + "corrupted_lsp_detected": "{{True if corrupted_lsp_detected is defined}}", + "attempt_to_exceed_max_sequence": "{{True if attempt_to_exceed_max_sequence is defined}}", + "max_area_addresses_mismatch": "{{True if max_area_addresses_mismatch is defined}}", + "own_lsp_purge": "{{True if own_lsp_purge is defined}}", + "sequence_number_skip": "{{True if sequence_number_skip is defined}}", + "authentication_type_failure": "{{True if authentication_type_failure is defined}}", + "authentication_failure": "{{True if authentication_failure is defined}}", + "version_skew": "{{True if version_skew is defined}}", + "area_mismatch": "{{True if area_mismatch is defined}}", + "rejected_adjacency": "{{True if rejected_adjacency is defined}}", + "lsp_too_large_to_propagate": "{{True if lsp_too_large_to_propagate is defined}}", + "orig_lsp_buff_size_mismatch": "{{True if orig_lsp_buff_size_mismatch is defined}}", + "protocols_supported_mismatch": "{{True if protocols_supported_mismatch is defined}}", + "adjacency_change": "{{True if adjacency_change is defined}}", + "lsp_error_detected": "{{True if lsp_error_detected is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2tun.pseudowire_status", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2tun\spseudowire-status(?P<pseudowire_status>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2tun pseudowire-status", + "result": { + "traps": { + + "l2tun": { + "pseudowire_status": "{{True if pseudowire_status is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2tun.sessions", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2tun\ssessions(?P<sessions>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2tun sessions", + "result": { + "traps": { + + "l2tun": { + "sessions": "{{True if sessions is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2tun.tunnel_down", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2tun\stunnel-down(?P<tunnel_down>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2tun tunnel-down", + "result": { + "traps": { + + "l2tun": { + "tunnel_down": "{{True if tunnel_down is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2tun.tunnel_up", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2tun\stunnel-up(?P<tunnel_up>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2tun tunnel-up", + "result": { + "traps": { + + "l2tun": { + "tunnel_up": "{{True if tunnel_up is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2vpn.all", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2vpn\sall(?P<vpnall>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2vpn all", + "result": { + "traps": { + + "l2vpn": { + "all": "{{True if vpnall is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2vpn.cisco", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2vpn\scisco(?P<cisco>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2vpn cisco", + "result": { + "traps": { + + "l2vpn": { + "cisco": "{{True if cisco is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2vpn.vc_up", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2vpn\svc-up(?P<vc_up>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2vpn vc-up", + "result": { + "traps": { + + "l2vpn": { + "vc_up": "{{True if vc_up is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.l2vpn.vc_down", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sl2vpn\svc-down(?P<vc_down>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps l2vpn vc-down", + "result": { + "traps": { + + "l2vpn": { + "vc_down": "{{True if vc_down is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.msdp_peer_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\smsdp\speer-state-change(?P<msdp>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps msdp peer-state-change", + "result": { + "traps": { + + "msdp_peer_state_change": "{{True if msdp is defined }}", + + }, + }, + }, + { + "name": "traps.ospf.retransmit.packets", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sretransmit\spackets(?P<packets>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf retransmit packets", + "result": { + "traps": { + + "ospf": { + + "retransmit": { + "packets": "{{True if packets is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.retransmit.virt_packets", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sretransmit\svirt-packets(?P<virt_packets>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf retransmit virt-packets", + "result": { + "traps": { + + "ospf": { + "retransmit": { + "virt_packets": "{{True if virt_packets is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.lsa.lsa_maxage", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\slsa\slsa-maxage(?P<lsa_maxage>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf lsa lsa-maxage", + "result": { + "traps": { + + "ospf": { + + "lsa": { + "lsa_maxage": "{{True if lsa_maxage is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.lsa.lsa_originate", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\slsa\slsa-originate(?P<lsa_originate>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf lsa lsa-originate", + "result": { + "traps": { + + "ospf": { + + "lsa": { + "lsa_originate": "{{True if lsa_originate is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.bad_packet", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\sbad-packet(?P<bad_packet>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors bad-packet", + "result": { + "traps": { + + "ospf": { + + "errors": { + "bad_packet": "{{True if bad_packet is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.authentication_failure", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\sauthentication-failure(?P<authentication_failure_ospf>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors authentication-failure", + "result": { + "traps": { + + "ospf": { + + "errors": { + "authentication_failure": "{{True if authentication_failure_ospf is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.config_error", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\sconfig-error(?P<config_error>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors config-error", + "result": { + "traps": { + + "ospf": { + + "errors": { + "config_error": "{{True if config_error is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.virt_bad_packet", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\svirt-bad-packet(?P<virt_bad_packet>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors virt-bad-packet", + "result": { + "traps": { + + "ospf": { + + "errors": { + "virt_bad_packet": "{{True if virt_bad_packet is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.virt_authentication_failure", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\svirt-authentication-failure(?P<virt_authentication_failure>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors virt-authentication-failure", + "result": { + "traps": { + + "ospf": { + + "errors": { + "virt_authentication_failure": "{{True if virt_authentication_failure is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.errors.virt_config_error", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\serrors\svirt-config-error(?P<virt_config_error>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf errors virt-config-error", + "result": { + "traps": { + + "ospf": { + + "errors": { + "virt_config_error": "{{True if virt_config_error is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.state_change.if_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sstate-change\sif-state-change(?P<if_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf state-change if-state-change", + "result": { + "traps": { + + "ospf": { + + "state_change": { + "if_state_change": "{{True if if_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.state_change.neighbor_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sstate-change\sneighbor-state-change(?P<neighbor_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf state-change neighbor-state-change", + "result": { + "traps": { + + "ospf": { + + "state_change": { + "neighbor_state_change": "{{True if neighbor_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.state_change.virtif_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sstate-change\svirtif-state-change(?P<virtif_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf state-change virtif-state-change", + "result": { + "traps": { + + "ospf": { + + "state_change": { + "virtif_state_change": "{{True if virtif_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospf.state_change.virtneighbor_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospf\sstate-change\svirtneighbor-state-change(?P<virtneighbor_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospf state-change virtneighbor-state-change", + "result": { + "traps": { + + "ospf": { + + "state_change": { + "virtneighbor_state_change": "{{True if virtneighbor_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.errors.bad_packet", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\serrors\sbad-packet(?P<bad_packet>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 errors bad-packet", + "result": { + "traps": { + + "ospfv3": { + + "errors": { + "bad_packet": "{{True if bad_packet is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.errors.authentication_failure", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\serrors\sauthentication-failure(?P<authentication_failure_ospf>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 errors authentication-failure", + "result": { + "traps": { + + "ospfv3": { + + "errors": { + "authentication_failure": "{{True if authentication_failure_ospf is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.errors.config_error", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\serrors\sconfig-error(?P<config_error>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 errors config-error", + "result": { + "traps": { + + "ospfv3": { + + "errors": { + "config_error": "{{True if config_error is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.errors.virt_config_error", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\serrors\svirt-config-error(?P<virt_config_error>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 errors virt-config-error", + "result": { + "traps": { + + "ospfv3": { + + "errors": { + "virt_config_error": "{{True if virt_config_error is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.errors.virt_bad_packet", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\serrors\svirt-bad-packet(?P<virt_bad_packet>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 errors virt-bad-packet", + "result": { + "traps": { + + "ospfv3": { + + "errors": { + "virt_bad_packet": "{{True if virt_bad_packet is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.if_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\sif-state-change(?P<if_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change if-state-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "if_state_change": "{{True if if_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.neighbor_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\sneighbor-state-change(?P<neighbor_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change neighbor-state-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "neighbor_state_change": "{{True if neighbor_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.virtif_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\svirtif-state-change(?P<virtif_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change virtif-state-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "virtif_state_change": "{{True if virtif_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.virtneighbor_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\svirtneighbor-state-change(?P<virtneighbor_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change virtneighbor-state-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "virtneighbor_state_change": "{{True if virtneighbor_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.restart_status_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\srestart-status-change(?P<restart_status_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change restart-status-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "restart_status_change": "{{True if restart_status_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.restart_helper_status_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\srestart-helper-status-change(?P<restart_helper_status_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change restart-helper-status-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "restart_helper_status_change": "{{True if restart_helper_status_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.restart_virtual_helper_status_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\srestart-virtual-helper-status-change(?P<restart_virtual_helper_status_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "restart_virtual_helper_status_change": "{{True if restart_virtual_helper_status_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.ospfv3.state_change.nssa_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sospfv3\sstate-change\snssa-state-change(?P<nssa_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps ospfv3 state-change nssa-state-change", + "result": { + "traps": { + + "ospfv3": { + + "state_change": { + "nssa_state_change": "{{True if nssa_state_change is defined}}", + + }, + + }, + + }, + }, + }, + { + "name": "traps.power", + "getval": re.compile( + r""" + ^snmp-server\straps + (\spower(?P<power>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps power", + "result": { + "traps": { + "power": "{{True if power is defined }}", + + }, + }, + }, + { + "name": "traps.rf", + "getval": re.compile( + r""" + ^snmp-server\straps + + + (\spower(?P<power>))? + (\srf(?P<rf>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps rf", + "result": { + "traps": { + "rf": "{{True if rf is defined}}", + + }, + }, + }, + { + "name": "traps.pim.neighbor_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\spim\sneighbor-change(?P<neighbor_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps pim neighbor-change", + "result": { + "traps": { + + "pim": { + + "neighbor_change": "{{True if neighbor_change is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.pim.invalid_message_received", + "getval": re.compile( + r""" + ^snmp-server\straps + + + + (\spim\sinvalid-message-received(?P<invalid_message_received>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps pim invalid-message-received", + "result": { + "traps": { + + "pim": { + + "invalid_message_received": "{{True if invalid_message_received is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.pim.rp_mapping_change", + "getval": re.compile( + r""" + ^snmp-server\straps + + + + (\spim\srp-mapping-change(?P<rp_mapping_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps pim rp-mapping-change", + "result": { + "traps": { + + "pim": { + + "rp_mapping_change": "{{True if rp_mapping_change is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.pim.interface_state_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\spim\sinterface-state-change(?P<interface_state_change>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps pim interface-state-change", + "result": { + "traps": { + "pim": { + "interface_state_change": "{{True if interface_state_change is defined}}", + }, + + }, + }, + }, + { + "name": "traps.rsvp.lost_flow", + "getval": re.compile( + r""" + ^snmp-server\straps + (\srsvp\slost-flow(?P<lost_flow>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps rsvp lost-flow", + "result": { + "traps": { + "rsvp": { + "lost_flow": "{{True if lost_flow is defined}}", + }, + }, + }, + }, + { + "name": "traps.rsvp.new_flow", + "getval": re.compile( + r""" + ^snmp-server\straps + (\srsvp\snew-flow(?P<new_flow>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps rsvp new-flow", + "result": { + "traps": { + "rsvp": { + "new_flow": "{{True if new_flow is defined}}", + }, + + }, + + }, + }, + { + "name": "traps.rsvp.all", + "getval": re.compile( + r""" + ^snmp-server\straps + (\srsvp\sall(?P<all>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps rsvp all", + "result": { + "traps": { + "rsvp": { + "all": "{{True if all is defined}}", + }, + + }, + + }, + }, + { + "name": "traps.selective_vrf_download_role_change", + "getval": re.compile( + r""" + ^snmp-server\straps + (\sselective-vrf-download\srole-change(?P<selective_vrf_download_role_change>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps selective-vrf-download role-change", + "result": { + "traps": { + "selective_vrf_download_role_change": "{{True if selective_vrf_download_role_change is defined}}", + }, + }, + }, + { + "name": "traps.sensor", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssensor(?P<sensor>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps sensor", + "result": { + "traps": {"sensor": "{{True if sensor is defined}}"}, + }, + }, + { + "name": "traps.vrrp_events", + "getval": re.compile( + r""" + ^snmp-server\straps + (\svrrp\sevents(?P<vrrp_events>))? + + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps vrrp events", + "result": { + + "traps": { + "vrrp_events": "{{True if vrrp_events is defined}}", + }, + }, + }, + { + "name": "traps.syslog", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssyslog(?P<syslog>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps syslog", + "result": { + "traps": {"syslog": "{{True if syslog is defined}}"}, + + }, + }, + { + "name": "traps.system", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssystem(?P<system>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps system", + "result": { + "traps": {"system": "{{True if system is defined}}"}, + + }, + }, + { + "name": "traps.subscriber.session_agg_access_interface", + "getval": re.compile( + r""" + ^snmp-server\straps + + (\ssubscriber\ssession-agg\saccess-interface(?P<session_agg_access_interface>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps subscriber session-agg access-interface", + "result": { + "traps": { + "subscriber": { + "session_agg_access_interface": "{{True if session_agg_access_interface is defined}}", + }, + }, + }, + }, + { + "name": "traps.subscriber.session_agg_node", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssubscriber\ssession-agg\snode(?P<session_agg_node>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps subscriber session-agg node", + "result": { + "traps": { + "subscriber": { + "session_agg_node": "{{True if session_agg_node is defined}}", + }, + + }, + }, + + }, + { + "name": "traps.vpls.all", + "getval": re.compile( + r""" + ^snmp-server\straps + + (\svpls\sall(?P<vpls_all>))? + + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps vpls all", + "result": { + "traps": { + + "vpls": { + "all": "{{True if vpls_all is defined}}", + + }, + + }, + }, + }, + { + "name": "traps.vpls.full_clear", + "getval": re.compile( + r""" + ^snmp-server\straps + (\svpls\sfull-clear(?P<full_clear>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps vpls full-clear", + "result": { + "traps": { + "vpls": { + "full_clear": "{{True if full_clear is defined}}", + }, + + }, + }, + }, + { + "name": "traps.vpls.full_raise", + "getval": re.compile( + r""" + ^snmp-server\straps + (\svpls\sfull-raise(?P<full_raise>))? + + $""", re.VERBOSE, + ), + "setval": "snmp-server traps vpls full-raise", + "result": { + "traps": { + "vpls": { + "full_raise": "{{True if full_raise is defined}}", + }, + + }, + }, + }, + { + "name": "traps.vpls.status", + "getval": re.compile( + r""" + ^snmp-server\straps + (\svpls\sstatus(?P<vpls_status>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps vpls status", + "result": { + "traps": { + "vpls": { + "status": "{{True if vpls_status is defined}}", + }, + + }, + }, + }, + { + "name": "traps.snmp.linkup", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssnmp\slinkup(?P<linkup>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps snmp linkup", + "result": { + "traps": { + "snmp": { + "linkup": "{{True if linkup is defined}}", + }, + }, + }, + }, + { + "name": "traps.snmp.linkdown", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssnmp\slinkdown(?P<linkdown>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps snmp linkdown", + "result": { + "traps": { + + "snmp": { + "linkdown": "{{True if linkdown is defined}}", + }, + }, + }, + }, + { + "name": "traps.snmp.coldstart", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssnmp\scoldstart(?P<coldstart>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps snmp coldstart", + "result": { + "traps": { + + "snmp": { + + "coldstart": "{{True if coldstart is defined}}", + + }, + }, + }, + }, + { + "name": "traps.snmp.warmstart", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssnmp\swarmstart(?P<warmstart>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps snmp warmstart", + "result": { + "traps": { + + "snmp": { + "warmstart": "{{True if warmstart is defined}}", + }, + }, + }, + }, + { + "name": "traps.snmp.authentication", + "getval": re.compile( + r""" + ^snmp-server\straps + (\ssnmp\sauthentication(?P<authentication>))? + $""", re.VERBOSE, + ), + "setval": "snmp-server traps snmp authentication", + "result": { + "traps": { + + "snmp": { + "authentication": "{{True if authentication is defined}}", + }, + }, + }, + }, + { + "name": "users", + "getval": re.compile( + r""" + ^snmp-server\suser + (\s(?P<name>\S+)) + (\s(?P<group>\S+)) + (\s(?P<version>v1|v2c|v3)) + (\sIPv4\s(?P<ipv4>\S+))? + (\sIPv6\s(?P<ipv6>\S+))? + (\s(?P<v4acl>\S+))? + (\sSDROwner\s(?P<sdrowner>))? + (\sSystemOwner\s(?P<systemowner>))? + $""", re.VERBOSE, + ), + "setval": user_tmplt, + "result": { + "users": [ + { + "user": "{{ name }}", + "group": "{{ group }}", + "acl_v4": "{{ipv4}}", + "acl_v6": "{{ipv6}}", + "SDROwner": "{{True if sdowner is defined}}", + "SystemOwner": "{{True if systemowner is defined }}", + "v4_acl": "{{v4acl}}", + "version": "{{version}}", + }, + ], + }, + }, + { + "name": "vrfs", + "getval": re.compile( + r""" + ^snmp-server\svrf + (\s(?P<vrf>\S+)) + (\scontext\s(?P<context>\S+))? + ((\shost\s(?P<host>\S+))? + (\s(?P<traps>traps))? + (\s(?P<informs>informs))? + (\sversion\s(?P<version>1|2c|3))? + (\s(?P<community>\S+))? + (\sudp-port\s(?P<port>\d+))?)? + $""", re.VERBOSE, + ), + "setval": "snmp-server vrf {{vrf}}", + "result": { + "vrfs": { + "{{vrf}}": { + "vrf": "{{vrf}}", + "context": { + "name_{{context|d()}}": "{{context}}", + }, + "hosts": [ + { + "host": "{{ host }}", + "traps": "{{True if traps is defined}}", + "informs": "{{True if informs is defined}}", + "community": "{{community}}", + "udp_port": "{{port}}", + "version": "{{version}}", + }, + ], + }, + }, + }, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/__init__.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/utils.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/utils.py new file mode 100644 index 00000000..a4467a48 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/utils/utils.py @@ -0,0 +1,456 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# utils + + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +from functools import total_ordering + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import missing_required_lib +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_diff, + is_masklen, + search_obj_in_list, + to_netmask, +) + + +try: + import ipaddress + + HAS_IPADDRESS = True +except ImportError: + HAS_IPADDRESS = False + + +def remove_command_from_config_list(interface, cmd, commands): + # To delete the passed config + if interface not in commands: + commands.insert(0, interface) + commands.append("no %s" % cmd) + return commands + + +def add_command_to_config_list(interface, cmd, commands): + # To set the passed config + if interface not in commands: + commands.insert(0, interface) + commands.append(cmd) + + +def dict_to_set(sample_dict): + # Generate a set with passed dictionary for comparison + test_dict = {} + if isinstance(sample_dict, dict): + for k, v in iteritems(sample_dict): + if v is not None: + if isinstance(v, list): + if isinstance(v[0], dict): + li = [] + for each in v: + for key, value in iteritems(each): + if isinstance(value, list): + each[key] = tuple(value) + li.append(tuple(iteritems(each))) + v = tuple(li) + else: + v = tuple(v) + elif isinstance(v, dict): + li = [] + for key, value in iteritems(v): + if isinstance(value, list): + v[key] = tuple(value) + li.extend(tuple(iteritems(v))) + v = tuple(li) + test_dict.update({k: v}) + return_set = set(tuple(iteritems(test_dict))) + else: + return_set = set(sample_dict) + return return_set + + +def filter_dict_having_none_value(want, have): + # Generate dict with have dict value which is None in want dict + test_dict = dict() + test_key_dict = dict() + name = want.get("name") + if name: + test_dict["name"] = name + diff_ip = False + want_ip = "" + for k, v in iteritems(want): + if isinstance(v, dict): + for key, value in iteritems(v): + if value is None and k in have and key in have.get(k): + dict_val = have.get(k).get(key) + test_key_dict.update({key: dict_val}) + test_dict.update({k: test_key_dict}) + if isinstance(v, list) and isinstance(v[0], dict): + for key, value in iteritems(v[0]): + if value is None and k in have and key in have.get(k): + dict_val = have.get(k).get(key) + test_key_dict.update({key: dict_val}) + test_dict.update({k: test_key_dict}) + # below conditions checks are added to check if + # secondary IP is configured, if yes then delete + # the already configured IP if want and have IP + # is different else if it's same no need to delete + for each in v: + if each.get("secondary"): + want_ip = each.get("address").split("/") + have_ip = have.get("ipv4") + for each in have_ip: + if len(want_ip) > 1 and each.get("secondary"): + have_ip = each.get("address").split(" ")[0] + if have_ip != want_ip[0]: + diff_ip = True + if each.get("secondary") and diff_ip is True: + test_key_dict.update({"secondary": True}) + test_dict.update({"ipv4": test_key_dict}) + # Checks if want doesn't have secondary IP but have has secondary IP set + elif have.get("ipv4"): + if [True for each_have in have.get("ipv4") if "secondary" in each_have]: + test_dict.update({"ipv4": {"secondary": True}}) + if k == "l2protocol": + diff = True + h_proto = have.get("l2protocol") + w_proto = want.get("l2protocol") + if h_proto: + if w_proto: + for h in h_proto: + for w in w_proto: + if h == w: + diff = False + if not diff: + break + else: + diff = True + if diff: + test_dict.update({k: v}) + if v is None: + val = have.get(k) + test_dict.update({k: val}) + return test_dict + + +def remove_duplicate_interface(commands): + # Remove duplicate interface from commands + set_cmd = [] + for each in commands: + if "interface" in each: + if each not in set_cmd: + set_cmd.append(each) + else: + set_cmd.append(each) + + return set_cmd + + +def flatten_dict(x): + result = {} + if not isinstance(x, dict): + return result + + for key, value in iteritems(x): + if isinstance(value, dict): + result.update(flatten_dict(value)) + else: + result[key] = value + + return result + + +def dict_delete(base, comparable): + """ + + This function generates a dict containing key, value pairs for keys + that are present in the `base` dict but not present in the `comparable` + dict. + + :param base: dict object to base the diff on + :param comparable: dict object to compare against base + + :returns: new dict object with key, value pairs that needs to be deleted. + + """ + to_delete = dict() + + for key in base: + if isinstance(base[key], dict): + sub_diff = dict_delete(base[key], comparable.get(key, {})) + if sub_diff: + to_delete[key] = sub_diff + else: + if key not in comparable: + to_delete[key] = base[key] + + return to_delete + + +def pad_commands(commands, interface): + commands.insert(0, "interface {0}".format(interface)) + + +def diff_list_of_dicts(w, h, key="member"): + """ + Returns a list containing diff between + two list of dictionaries + """ + if not w: + w = [] + if not h: + h = [] + + diff = [] + for w_item in w: + h_item = search_obj_in_list(w_item[key], h, key=key) or {} + d = dict_diff(h_item, w_item) + if d: + if key not in d.keys(): + d[key] = w_item[key] + diff.append(d) + + return diff + + +def validate_ipv4(value, module): + if value: + address = value.split("/") + if len(address) != 2: + module.fail_json( + msg="address format is <ipv4 address>/<mask>, got invalid format {0}".format( + value, + ), + ) + + if not is_masklen(address[1]): + module.fail_json( + msg="invalid value for mask: {0}, mask should be in range 0-32".format( + address[1], + ), + ) + + +def validate_ipv6(value, module): + if value: + address = value.split("/") + if len(address) != 2: + module.fail_json( + msg="address format is <ipv6 address>/<mask>, got invalid format {0}".format( + value, + ), + ) + else: + if not 0 <= int(address[1]) <= 128: + module.fail_json( + msg="invalid value for mask: {0}, mask should be in range 0-128".format( + address[1], + ), + ) + + +def validate_n_expand_ipv4(module, want): + # Check if input IPV4 is valid IP and expand IPV4 with its subnet mask + ip_addr_want = want.get("address") + if len(ip_addr_want.split(" ")) > 1: + return ip_addr_want + validate_ipv4(ip_addr_want, module) + ip = ip_addr_want.split("/") + if len(ip) == 2: + ip_addr_want = "{0} {1}".format(ip[0], to_netmask(ip[1])) + + return ip_addr_want + + +def normalize_interface(name): + """Return the normalized interface name""" + if not name: + return + + def _get_number(name): + digits = "" + for char in name: + if char.isdigit() or char in "/.": + digits += char + return digits + + if name.lower().startswith("gi"): + if_type = "GigabitEthernet" + elif name.lower().startswith("fa"): + if_type = "FastEthernet" + elif name.lower().startswith("fo"): + if_type = "FortyGigE" + elif name.lower().startswith("te"): + if_type = "TenGigE" + elif name.lower().startswith("twe"): + if_type = "TwentyFiveGigE" + elif name.lower().startswith("hu"): + if_type = "HundredGigE" + elif name.lower().startswith("vl"): + if_type = "Vlan" + elif name.lower().startswith("lo"): + if_type = "Loopback" + elif name.lower().startswith("be"): + if_type = "Bundle-Ether" + elif name.lower().startswith("bp"): + if_type = "Bundle-POS" + else: + if_type = None + + number_list = name.split(" ") + if len(number_list) == 2: + number = number_list[-1].strip() + else: + number = _get_number(name) + + if if_type: + proper_interface = if_type + number + else: + proper_interface = name + + return proper_interface + + +def get_interface_type(interface): + """Gets the type of interface""" + + if interface.upper().startswith("GI"): + return "GigabitEthernet" + elif interface.upper().startswith("FA"): + return "FastEthernet" + elif interface.upper().startswith("FO"): + return "FortyGigE" + elif interface.upper().startswith("ET"): + return "Ethernet" + elif interface.upper().startswith("LO"): + return "Loopback" + elif interface.upper().startswith("BE"): + return "Bundle-Ether" + elif interface.upper().startswith("NV"): + return "nve" + elif interface.upper().startswith("TE"): + return "TenGigE" + elif interface.upper().startswith("TWE"): + return "TwentyFiveGigE" + elif interface.upper().startswith("HU"): + return "HundredGigE" + elif interface.upper().startswith("PRE"): + return "preconfigure" + else: + return "unknown" + + +def isipaddress(data): + """ + Checks if the passed string is + a valid IPv4 or IPv6 address + """ + if not HAS_IPADDRESS: + raise Exception(missing_required_lib("ipaddress")) + isipaddress = True + + try: + ipaddress.ip_address(data) + except ValueError: + isipaddress = False + + return isipaddress + + +def is_ipv4_address(data): + """ + Checks if the passed string is + a valid IPv4 address + """ + if not HAS_IPADDRESS: + raise Exception(missing_required_lib("ipaddress")) + if "/" in data: + data = data.split("/")[0] + + if not isipaddress(to_text(data)): + raise ValueError("{0} is not a valid IP address".format(data)) + + return ipaddress.ip_address(to_text(data)).version == 4 + + +def prefix_to_address_wildcard(prefix): + """Converts a IPv4 prefix into address and + wildcard mask + + :returns: IPv4 address and wildcard mask + """ + if not HAS_IPADDRESS: + raise Exception(missing_required_lib("ipaddress")) + wildcard = [] + + subnet = to_text(ipaddress.IPv4Network(to_text(prefix)).netmask) + + for x in subnet.split("."): + component = 255 - int(x) + wildcard.append(str(component)) + + wildcard = ".".join(wildcard) + + return prefix.split("/")[0], wildcard + + +def flatten_config(data, context): + """Flatten different contexts in + the running-config for easier parsing. + :param data: dict + :param context: str + :returns: flattened running config + """ + data = data.split("\n") + in_cxt = False + cur = {} + + for index, x in enumerate(data): + cur_indent = len(x) - len(x.lstrip()) + if x.strip().startswith(context): + in_cxt = True + cur["context"] = x + cur["indent"] = cur_indent + elif cur and (cur_indent <= cur["indent"]): + in_cxt = False + elif in_cxt: + data[index] = cur["context"] + " " + x.strip() + return "\n".join(data) + + +@total_ordering +class Version: + """Simple class to compare arbitrary versions""" + + def __init__(self, version_string): + self.components = version_string.split(".") + + def __eq__(self, other): + other = _coerce(other) + if not isinstance(other, Version): + return NotImplemented + + return self.components == other.components + + def __lt__(self, other): + other = _coerce(other) + if not isinstance(other, Version): + return NotImplemented + + return self.components < other.components + + +def _coerce(other): + if isinstance(other, str): + other = Version(other) + if isinstance(other, (int, float)): + other = Version(str(other)) + return other diff --git a/ansible_collections/cisco/iosxr/plugins/modules/__init__.py b/ansible_collections/cisco/iosxr/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acl_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acl_interfaces.py new file mode 100644 index 00000000..7dc8df80 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acl_interfaces.py @@ -0,0 +1,653 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_acl_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_acl_interfaces +short_description: Resource module to configure ACL interfaces. +description: +- This module manages adding and removing Access Control Lists (ACLs) from interfaces + on devices running IOS-XR software. +version_added: 1.0.0 +author: Nilashish Chakraborty (@NilashishC) +options: + config: + description: A dictionary of ACL options for interfaces. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier for the interface + type: str + required: true + access_groups: + type: list + elements: dict + description: + - Specifies ACLs attached to the interfaces. + suboptions: + afi: + description: + - Specifies the AFI for the ACL(s) to be configured on this interface. + type: str + choices: + - ipv4 + - ipv6 + required: true + acls: + type: list + description: + - Specifies the ACLs for the provided AFI. + elements: dict + suboptions: + name: + description: + - Specifies the name of the IPv4/IPv6 ACL for the interface. + type: str + required: true + direction: + description: + - Specifies the direction of packets that the ACL will be applied + on. + type: str + choices: + - in + - out + required: true + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:22:32.911 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! + +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + access_groups: + - afi: ipv4 + acls: + - name: acl_1 + direction: in + - name: acl_2 + direction: out + - afi: ipv6 + acls: + - name: acl6_1 + direction: in + - name: acl6_2 + direction: out + + - name: GigabitEthernet0/0/0/1 + access_groups: + - afi: ipv4 + acls: + - name: acl_1 + direction: out + state: merged + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:27:49.378 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! + +# Using merged to update interface ACL configuration + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:27:49.378 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! +# + +- name: Update acl_interfaces configuration using merged + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + access_groups: + - afi: ipv4 + acls: + - name: acl_2 + direction: out + - name: acl_1 + direction: in + state: merged + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:27:49.378 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ! +# + +# Using replaced + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! + +- name: Replace device configurations of listed interface with provided configurations + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + access_groups: + - afi: ipv6 + acls: + - name: acl6_3 + direction: in + state: replaced + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv6 access-group acl6_3 ingress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! +# + +# Using overridden + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! +# + +- name: Overridde all interface ACL configuration with provided configuration + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + access_groups: + - afi: ipv4 + acls: + - name: acl_2 + direction: in + - afi: ipv6 + acls: + - name: acl6_3 + direction: out + state: overridden + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_2 ingress +# ipv6 access-group acl6_3 egress +# ! +# + +# Using 'deleted' to delete all ACL attributes of a single interface + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! +# + +- name: Delete all ACL attributes of GigabitEthernet0/0/0/1 + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + state: deleted + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# + +# Using 'deleted' to remove all ACLs attached to all the interfaces in the device + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! +# + +- name: Delete all ACL interfaces configuration from the device + cisco.iosxr.iosxr_acl_interfaces: + state: deleted + +# After state: +# ------------- +# +# RP/0/RP0/CPU0:ios#sh running-config interface +# Wed Jan 15 12:34:56.689 UTC +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# + +# Using parsed + +# parsed.cfg +# ------------ +# +# interface MgmtEth0/RP0/CPU0/0 +# ipv4 address dhcp +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ipv4 access-group acl_1 ingress +# ipv4 access-group acl_2 egress +# ipv6 access-group acl6_1 ingress +# ipv6 access-group acl6_2 egress +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ipv4 access-group acl_1 egress +# ! + +# - name: Convert ACL interfaces config to argspec without connecting to the appliance +# cisco.iosxr.iosxr_acl_interfaces: +# running_config: "{{ lookup('file', './parsed.cfg') }}" +# state: parsed + + +# Task Output (redacted) +# ----------------------- + +# "parsed": [ +# { +# "name": "MgmtEth0/RP0/CPU0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl_1" +# }, +# { +# "direction": "out", +# "name": "acl_2" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl6_1" +# }, +# { +# "direction": "out", +# "name": "acl6_2" +# } +# ], +# "afi": "ipv6" +# } +# ], +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "out", +# "name": "acl_1" +# } +# ], +# "afi": "ipv4" +# } +# ], +# "name": "GigabitEthernet0/0/0/1" +# } +# ] +# } + + +# Using gathered + +- name: Gather ACL interfaces facts using gathered state + cisco.iosxr.iosxr_acl_interfaces: + state: gathered + + +# Task Output (redacted) +# ----------------------- +# +# "gathered": [ +# { +# "name": "MgmtEth0/RP0/CPU0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl_1" +# }, +# { +# "direction": "out", +# "name": "acl_2" +# } +# ], +# "afi": "ipv4" +# } +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl6_1" +# } +# ], +# "afi": "ipv6" +# } +# "name": "GigabitEthernet0/0/0/1" +# } +# ] + + +# Using rendered + +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_acl_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + access_groups: + - afi: ipv4 + acls: + - name: acl_1 + direction: in + - name: acl_2 + direction: out + state: rendered + +# Task Output (redacted) +# ----------------------- + +# "rendered": [ +# "interface GigabitEthernet0/0/0/0", +# "ipv4 access-group acl_1 ingress", +# "ipv4 access-group acl_2 egress" +# ] +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + 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: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - "interface GigabitEthernet0/0/0/1" + - "ipv4 access-group acl_1 ingress" + - "ipv4 access-group acl_2 egress" + - "ipv6 access-group acl6_1 ingress" + - "interface GigabitEthernet0/0/0/2" + - "no ipv4 access-group acl_3 ingress" + - "ipv4 access-group acl_4 egress" +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.acl_interfaces.acl_interfaces import ( + Acl_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.acl_interfaces.acl_interfaces import ( + Acl_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Acl_interfacesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Acl_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acls.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acls.py new file mode 100644 index 00000000..22a7779c --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_acls.py @@ -0,0 +1,1467 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_acls +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_acls +short_description: Resource module to configure ACLs. +description: +- This module manages Access Control Lists (ACLs) on devices running IOS-XR. +version_added: 1.0.0 +author: Nilashish Chakraborty (@NilashishC) +options: + config: + description: A list of dictionaries specifying ACL configurations. + type: list + elements: dict + suboptions: + afi: + description: + - The Address Family Indicator (AFI) for the Access Control Lists (ACL). + type: str + required: true + choices: + - ipv4 + - ipv6 + acls: + description: + - A list of Access Control Lists (ACLs). + type: list + elements: dict + suboptions: + name: + description: + - The name of the Access Control List (ACL). + type: str + aces: + description: + - List of Access Control Entries (ACEs) for this Access Control List (ACL). + type: list + elements: dict + suboptions: + sequence: + description: + - Sequence number for the Access Control Entry (ACE). + type: int + grant: + description: + - Forward or drop packets matching the Access Control Entry (ACE). + type: str + choices: + - permit + - deny + remark: + description: + - Comments or a description for the access list. + type: str + line: + description: + - An ACE excluding the sequence number. + - This key is mutually exclusive with all the other attributes except + 'sequence'. + - When used with other attributes, the value of this key will get + precedence and the other keys will be ignored. + - This should only be used when an attribute doesn't exist in the + argspec but is valid for the device. + - For fact gathering, any ACE that is not fully parsed, will show + up as a value of this attribute, excluding the sequence number, + which will be populated as value of the sequence key. + type: str + aliases: + - ace + source: + description: + - Specifies the packet source. + type: dict + suboptions: + host: + description: + - The host IP address to match. + type: str + net_group: + description: + - Name of net-group. + type: str + port_group: + description: + - Name of port-group. + type: str + address: + description: + - The source IP address to match. + type: str + wildcard_bits: + description: + - The Wildcard bits to apply to source address. + type: str + any: + description: + - Match any source address. + type: bool + prefix: + description: + - Source network prefix. + type: str + port_protocol: + description: + - Specify the source port or protocol. + type: dict + suboptions: + eq: + description: + - Match only packets on a given port number. + type: str + gt: + description: + - Match only packets with a greater port number. + type: str + lt: + description: + - Match only packets with a lower port number. + type: str + neq: + description: + - Match only packets not on a given port number. + type: str + range: + description: + - Match only packets in the range of port numbers + type: dict + suboptions: + start: + description: + - Specify the start of the port range + type: str + end: + description: + - Specify the end of the port range + type: str + destination: + description: + - Specifies the packet destination. + type: dict + suboptions: + host: + description: + - The host IP address to match. + type: str + net_group: + description: + - Name of net-group. + type: str + port_group: + description: + - Name of port-group. + type: str + address: + description: + - The destination IP address to match. + type: str + wildcard_bits: + description: + - The Wildcard bits to apply to destination address. + type: str + any: + description: + - Match any destination address. + type: bool + prefix: + description: + - Destination network prefix. + type: str + port_protocol: + description: + - Specify the source port or protocol. + type: dict + suboptions: + eq: + description: + - Match only packets on a given port number. + type: str + gt: + description: + - Match only packets with a greater port number. + type: str + lt: + description: + - Match only packets with a lower port number. + type: str + neq: + description: + - Match only packets not on a given port number. + type: str + range: + description: + - Match only packets in the range of port numbers + type: dict + suboptions: + start: + description: + - Specify the start of the port range + type: str + end: + description: + - Specify the end of the port range + type: str + protocol: + description: + - Specify the protocol to match. + - Refer to vendor documentation for valid values. + type: str + protocol_options: + description: + - Additional suboptions for the protocol. + type: dict + suboptions: + icmpv6: + description: Internet Control Message Protocol settings for IPv6. + type: dict + suboptions: + address_unreachable: + description: Address Unreachable + type: bool + administratively_prohibited: + description: Administratively Prohibited + type: bool + beyond_scope_of_source_address: + description: Administratively Prohibited + type: bool + destination_unreachable: + description: Destination Unreachable + type: bool + echo: + description: Echo + type: bool + echo_reply: + description: Echo Reply + type: bool + erroneous_header_field: + description: Erroneous Header Field + type: bool + group_membership_query: + description: Group Membership Query + type: bool + group_membership_report: + description: Group Membership Report + type: bool + group_membership_termination: + description: Group Membership Termination + type: bool + host_unreachable: + description: Host Unreachable + type: bool + nd_na: + description: Neighbor Discovery - Neighbor Advertisement + type: bool + nd_ns: + description: Neighbor Discovery - Neighbor Solicitation + type: bool + neighbor_redirect: + description: Neighbor Redirect + type: bool + no_route_to_destination: + description: No Route To Destination + type: bool + node_information_request_is_refused: + description: Node Information Request Is Refused + type: bool + node_information_successful_reply: + description: Node Information Successful Reply + type: bool + packet_too_big: + description: Packet Too Big + type: bool + parameter_problem: + description: Parameter Problem + type: bool + port_unreachable: + description: Port Unreachable + type: bool + query_subject_is_IPv4address: + description: Query Subject Is IPv4 address + type: bool + query_subject_is_IPv6address: + description: Query Subject Is IPv6 address + type: bool + query_subject_is_domainname: + description: Query Subject Is Domain name + type: bool + reassembly_timeout: + description: Reassembly Timeout + type: bool + redirect: + description: Redirect + type: bool + router_advertisement: + description: Router Advertisement + type: bool + router_renumbering: + description: Router Renumbering + type: bool + router_solicitation: + description: Router Solicitation + type: bool + rr_command: + description: RR Command + type: bool + rr_result: + description: RR Result + type: bool + rr_seqnum_reset: + description: RR Seqnum Reset + type: bool + time_exceeded: + description: Time Exceeded + type: bool + ttl_exceeded: + description: TTL Exceeded + type: bool + unknown_query_type: + description: Unknown Query Type + type: bool + unreachable: + description: Unreachable + type: bool + unrecognized_next_header: + description: Unrecognized Next Header + type: bool + unrecognized_option: + description: Unrecognized Option + type: bool + whoareyou_reply: + description: Whoareyou Reply + type: bool + whoareyou_request: + description: Whoareyou Request + type: bool + icmp: + description: Internet Control Message Protocol settings. + type: dict + suboptions: + administratively_prohibited: + description: Administratively prohibited + type: bool + alternate_address: + description: Alternate address + type: bool + conversion_error: + description: Datagram conversion + type: bool + dod_host_prohibited: + description: Host prohibited + type: bool + dod_net_prohibited: + description: Net prohibited + type: bool + echo: + description: Echo (ping) + type: bool + echo_reply: + description: Echo reply + type: bool + general_parameter_problem: + description: Parameter problem + type: bool + host_isolated: + description: Host isolated + type: bool + host_precedence_unreachable: + description: Host unreachable for precedence + type: bool + host_redirect: + description: Host redirect + type: bool + host_tos_redirect: + description: Host redirect for TOS + type: bool + host_tos_unreachable: + description: Host unreachable for TOS + type: bool + host_unknown: + description: Host unknown + type: bool + host_unreachable: + description: Host unreachable + type: bool + information_reply: + description: Information replies + type: bool + information_request: + description: Information requests + type: bool + mask_reply: + description: Mask replies + type: bool + mask_request: + description: Mask requests + type: bool + mobile_redirect: + description: Mobile host redirect + type: bool + net_redirect: + description: Network redirect + type: bool + net_tos_redirect: + description: Net redirect for TOS + type: bool + net_tos_unreachable: + description: Network unreachable for TOS + type: bool + net_unreachable: + description: Net unreachable + type: bool + network_unknown: + description: Network unknown + type: bool + no_room_for_option: + description: Parameter required but no room + type: bool + option_missing: + description: Parameter required but not present + type: bool + packet_too_big: + description: Fragmentation needed and DF set + type: bool + parameter_problem: + description: All parameter problems + type: bool + port_unreachable: + description: Port unreachable + type: bool + precedence_unreachable: + description: Precedence cutoff + type: bool + protocol_unreachable: + description: Protocol unreachable + type: bool + reassembly_timeout: + description: Reassembly timeout + type: bool + redirect: + description: All redirects + type: bool + router_advertisement: + description: Router discovery advertisements + type: bool + router_solicitation: + description: Router discovery solicitations + type: bool + source_quench: + description: Source quenches + type: bool + source_route_failed: + description: Source route failed + type: bool + time_exceeded: + description: All time exceededs + type: bool + timestamp_reply: + description: Timestamp replies + type: bool + timestamp_request: + description: Timestamp requests + type: bool + traceroute: + description: Traceroute + type: bool + ttl_exceeded: + description: TTL exceeded + type: bool + unreachable: + description: All unreachables + type: bool + tcp: + description: Match TCP packet flags + type: dict + suboptions: + ack: + description: Match on the ACK bit + type: bool + established: + description: Match established connections + type: bool + fin: + description: Match on the FIN bit + type: bool + psh: + description: Match on the PSH bit + type: bool + rst: + description: Match on the RST bit + type: bool + syn: + description: Match on the SYN bit + type: bool + urg: + description: Match on the URG bit + type: bool + igmp: + description: Internet Group Management Protocol (IGMP) settings. + type: dict + suboptions: + dvmrp: + description: Match Distance Vector Multicast Routing Protocol + type: bool + host_query: + description: Match Host Query + type: bool + host_report: + description: Match Host Report + type: bool + pim: + description: Match Protocol Independent Multicast + type: bool + trace: + description: Multicast trace + type: bool + mtrace: + description: Match mtrace + type: bool + mtrace_response: + description: Match mtrace response + type: bool + dscp: + description: + - Match packets with given DSCP value. + type: dict + suboptions: + eq: + description: Match only packets on a given dscp value + type: str + gt: + description: Match only packets with a greater dscp value + type: str + lt: + description: Match only packets with a lower dscp value + type: str + neq: + description: Match only packets not on a given dscp value + type: str + range: + description: Match only packets in the range of dscp values + type: dict + suboptions: + start: + description: Start of the dscp range + type: str + end: + description: End of the dscp range + type: str + fragments: + description: + - Check non-intial fragments. + type: bool + packet_length: + description: + - Match packets given packet length. + type: dict + suboptions: + eq: + description: Match only packets on a given packet length + type: int + gt: + description: Match only packets with a greater packet length + type: int + lt: + description: Match only packets with a lower packet length + type: int + neq: + description: Match only packets not on a given packet length + type: int + range: + description: Match only packets in the range of packet lengths + type: dict + suboptions: + start: + description: Start of the packet length range + type: int + end: + description: End of the packet length range + type: int + precedence: + description: Match packets with given precedence value + type: str + ttl: + description: Match against specified TTL value. + type: dict + suboptions: + eq: + description: Match only packets with exact TTL value. + type: int + gt: + description: Match only packets with a greater TTL value. + type: int + lt: + description: Match only packets with a lower TTL value. + type: int + neq: + description: Match only packets that won't have the given TTL + value. + type: int + range: + description: Match only packets in the range of given TTL values. + type: dict + suboptions: + start: + description: Start of the TTL range. + type: int + end: + description: End of the TTL range. + type: int + log: + description: + - Enable/disable log matches against this entry. + type: bool + log_input: + description: + - Enable/disable log matches against this entry, including input interface. + type: bool + icmp_off: + description: + - Enable/disable the ICMP message for this entry. + type: bool + capture: + description: + - Capture matched packet. + type: bool + destopts: + description: + - Match if destination opts header is present. + type: bool + authen: + description: + - Match if authentication header is present. + type: bool + routing: + description: + - Match if routing header is present. + type: bool + hop_by_hop: + description: + - Match if hop-by-hop opts header is present. + type: bool + 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 B(show running-config router static). + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged + +""" +EXAMPLES = """ +# Using merged to add new ACLs + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:07:45.767 UTC +# RP/0/RP0/CPU0:ios# + +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_acls: + config: + - afi: ipv6 + acls: + - name: acl6_1 + aces: + - sequence: 10 + grant: deny + protocol: tcp + source: + prefix: 2001:db8:1234::/48 + port_protocol: + range: + start: ftp + end: telnet + destination: + any: true + protocol_options: + tcp: + syn: true + ttl: + range: + start: 180 + end: 250 + routing: true + authen: true + log: true + + - sequence: 20 + grant: permit + protocol: icmpv6 + source: + any: true + destination: + any: true + protocol_options: + icmpv6: + router_advertisement: true + precedence: network + destopts: true + + - afi: ipv4 + acls: + - name: acl_1 + aces: + - sequence: 16 + remark: TEST_ACL_1_REMARK + + - sequence: 21 + grant: permit + protocol: tcp + source: + host: 192.0.2.10 + port_protocol: + range: + start: pop3 + end: 121 + destination: + address: 198.51.100.0 + wildcard_bits: 0.0.0.15 + protocol_options: + tcp: + rst: true + + - sequence: 23 + grant: deny + protocol: icmp + source: + any: true + destination: + prefix: 198.51.100.0/28 + protocol_options: + icmp: + reassembly_timeout: true + dscp: + lt: af12 + + - name: acl_2 + aces: + - sequence: 10 + remark: TEST_ACL_2_REMARK + state: merged + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +# Using merged to update existing ACLs + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Update existing ACEs + cisco.iosxr.iosxr_acls: + config: + - afi: ipv4 + acls: + - name: acl_1 + aces: + - sequence: 21 + source: + prefix: 198.51.100.32/28 + port_protocol: + range: + start: pop3 + end: 121 + protocol_options: + tcp: + syn: true + + - sequence: 23 + protocol_options: + icmp: + router_advertisement: true + dscp: + eq: af23 + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:47:18.711 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp 198.51.100.32 0.0.0.15 range pop3 121 198.51.100.0 0.0.0.15 syn +# 23 deny icmp any 198.51.100.0 0.0.0.15 router-advertisement dscp eq af23 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +# Using replaced to replace a whole ACL + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Replace device configurations of listed ACL with provided configurations + cisco.iosxr.iosxr_acls: + config: + - afi: ipv4 + acls: + - name: acl_2 + aces: + - sequence: 11 + grant: permit + protocol: igmp + source: + host: 198.51.100.130 + destination: + any: true + ttl: + eq: 100 + + - sequence: 12 + grant: deny + source: + any: true + destination: + any: true + protocol: icmp + state: replaced + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 06:19:51.496 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp 198.51.100.32 0.0.0.15 range pop3 121 198.51.100.0 0.0.0.15 syn +# 23 deny icmp any 198.51.100.0 0.0.0.15 router-advertisement dscp eq af23 +# ipv4 access-list acl_2 +# 11 permit igmp host 198.51.100.130 any ttl eq 100 +# 12 deny icmp any any +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +# Using overridden to override all ACLs in the device + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Overridde all ACLs configuration with provided configuration + cisco.iosxr.iosxr_acls: + config: + - afi: ipv4 + acls: + - name: acl_1 + aces: + - sequence: 10 + grant: permit + source: + any: true + destination: + any: true + protocol: tcp + + - name: acl_2 + aces: + - sequence: 20 + grant: permit + source: + any: true + destination: + any: true + protocol: igmp + state: overridden + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 06:31:22.178 UTC +# ipv4 access-list acl_1 +# 10 permit tcp any any +# ipv4 access-list acl_2 +# 20 permit igmp any any + +# Using deleted to delete an entire ACL + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Delete a single ACL + cisco.iosxr.iosxr_acls: + config: + - afi: ipv6 + acls: + - name: acl6_1 + state: deleted + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK + +# Using deleted to delete all ACLs under one AFI + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Delete all ACLs under one AFI + cisco.iosxr.iosxr_acls: + config: + - afi: ipv4 + state: deleted + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +# Using deleted to delete all ACLs from the device + +# Before state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:22:57.021 UTC +# ipv4 access-list acl_1 +# 16 remark TEST_ACL_1_REMARK +# 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst +# 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +# ipv4 access-list acl_2 +# 10 remark TEST_ACL_2_REMARK +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network destopts + +- name: Delete all ACLs from the device + cisco.iosxr.iosxr_acls: + state: deleted + +# After state: +# ------------- + +# RP/0/RP0/CPU0:ios#sh access-lists afi-all +# Thu Feb 20 05:07:45.767 UTC +# RP/0/RP0/CPU0:ios# + +# Using gathered to gather ACL facts from the device + +- name: Gather ACL interfaces facts using gathered state + cisco.iosxr.iosxr_acls: + state: gathered + +# Task Output (redacted) +# ----------------------- +# + +# "gathered": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "remark": "TEST_ACL_1_REMARK", +# "sequence": 16 +# }, +# { +# "destination": { +# "address": "198.51.100.0", +# "wildcard_bits": "0.0.0.15" +# }, +# "grant": "permit", +# "protocol": "tcp", +# "protocol_options": { +# "tcp": { +# "rst": true +# } +# }, +# "sequence": 21, +# "source": { +# "host": "192.0.2.10", +# "port_protocol": { +# "range": { +# "end": "121", +# "start": "pop3" +# } +# } +# } +# }, +# { +# "destination": { +# "address": "198.51.100.0", +# "wildcard_bits": "0.0.0.15" +# }, +# "dscp": { +# "lt": "af12" +# }, +# "grant": "deny", +# "protocol": "icmp", +# "protocol_options": { +# "icmp": { +# "reassembly_timeout": true +# } +# }, +# "sequence": 23, +# "source": { +# "any": true +# } +# } +# ], +# "name": "acl_1" +# }, +# { +# "aces": [ +# { +# "remark": "TEST_ACL_2_REMARK", +# "sequence": 10 +# } +# ], +# "name": "acl_2" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "aces": [ +# { +# "authen": true, +# "destination": { +# "any": true +# }, +# "grant": "deny", +# "log": true, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": { +# "syn": true +# } +# }, +# "routing": true, +# "sequence": 10, +# "source": { +# "port_protocol": { +# "range": { +# "end": "telnet", +# "start": "ftp" +# } +# }, +# "prefix": "2001:db8:1234::/48" +# }, +# "ttl": { +# "range": { +# "end": 250, +# "start": 180 +# } +# } +# }, +# { +# "destination": { +# "any": true +# }, +# "destopts": true, +# "grant": "permit", +# "precedence": "network", +# "protocol": "icmpv6", +# "protocol_options": { +# "icmpv6": { +# "router_advertisement": true +# } +# }, +# "sequence": 20, +# "source": { +# "any": true +# } +# } +# ], +# "name": "acl6_1" +# } +# ], +# "afi": "ipv6" +# } +# ] + +# Using rendered + +- name: Render platform specific commands (without connecting to the device) + cisco.iosxr.iosxr_acls: + config: + - afi: ipv4 + acls: + - name: acl_2 + aces: + - sequence: 11 + grant: permit + protocol: igmp + source: + host: 198.51.100.130 + destination: + any: true + ttl: + eq: 100 + + - sequence: 12 + grant: deny + source: + any: true + destination: + any: true + protocol: icmp + state: rendered + +# Task Output (redacted) +# ----------------------- + +# "rendered": [ +# "ipv4 access-list acl_2", +# "11 permit igmp host 198.51.100.130 any ttl eq 100", +# "12 deny icmp any any" + +# Using parsed + +# parsed.cfg +# ------------ +# +# ipv4 access-list acl_1 +# 10 remark TEST_ACL_2_REMARK +# ipv4 access-list acl_2 +# 11 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 authen routing log +# 21 permit icmpv6 any any router-advertisement precedence network packet-length eq 576 destopts +# ipv6 access-list acl6_1 +# 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 routing authen log +# 20 permit icmpv6 any any router-advertisement precedence network packet-length eq 576 destopts + +- name: Parse externally provided ACL config to agnostic model + cisco.iosxr.iosxr_acls: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Task Output (redacted) +# ----------------------- +# "parsed": [ +# { +# "acls": [ +# { +# "aces": [ +# { +# "remark": "TEST_ACL_2_REMARK", +# "sequence": 10 +# } +# ], +# "name": "acl_1" +# }, +# { +# "aces": [ +# { +# "authen": true, +# "destination": { +# "any": true +# }, +# "grant": "deny", +# "log": true, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": { +# "syn": true +# } +# }, +# "routing": true, +# "sequence": 11, +# "source": { +# "port_protocol": { +# "range": { +# "end": "telnet", +# "start": "ftp" +# } +# }, +# "prefix": "2001:db8:1234::/48" +# }, +# "ttl": { +# "range": { +# "end": 250, +# "start": 180 +# } +# } +# }, +# { +# "destination": { +# "any": true +# }, +# "destopts": true, +# "grant": "permit", +# "packet_length": { +# "eq": 576 +# }, +# "precedence": "network", +# "protocol": "icmpv6", +# "protocol_options": { +# "icmpv6": { +# "router_advertisement": true +# } +# }, +# "sequence": 21, +# "source": { +# "any": true +# } +# } +# ], +# "name": "acl_2" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "aces": [ +# { +# "authen": true, +# "destination": { +# "any": true +# }, +# "grant": "deny", +# "log": true, +# "protocol": "tcp", +# "protocol_options": { +# "tcp": { +# "syn": true +# } +# }, +# "routing": true, +# "sequence": 10, +# "source": { +# "port_protocol": { +# "range": { +# "end": "telnet", +# "start": "ftp" +# } +# }, +# "prefix": "2001:db8:1234::/48" +# }, +# "ttl": { +# "range": { +# "end": 250, +# "start": 180 +# } +# } +# }, +# { +# "destination": { +# "any": true +# }, +# "destopts": true, +# "grant": "permit", +# "packet_length": { +# "eq": 576 +# }, +# "precedence": "network", +# "protocol": "icmpv6", +# "protocol_options": { +# "icmpv6": { +# "router_advertisement": true +# } +# }, +# "sequence": 20, +# "source": { +# "any": true +# } +# } +# ], +# "name": "acl6_1" +# } +# ], +# "afi": "ipv6" +# } +# ] +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + 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: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - ipv6 access-list acl6_1 + - 10 deny tcp 2001:db8:1234::/48 range ftp telnet any syn ttl range 180 250 authen routing log + - 20 permit icmpv6 any any router-advertisement precedence network destopts + - ipv4 access-list acl_1 + - 16 remark TEST_ACL_1_REMARK + - 21 permit tcp host 192.0.2.10 range pop3 121 198.51.100.0 0.0.0.15 rst + - 23 deny icmp any 198.51.100.0 0.0.0.15 reassembly-timeout dscp lt af12 +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.acls.acls import ( + AclsArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.acls.acls import Acls + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + module = AnsibleModule( + argument_spec=AclsArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + + result = Acls(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_banner.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_banner.py new file mode 100644 index 00000000..2d80022b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_banner.py @@ -0,0 +1,285 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_banner +author: +- Trishna Guha (@trishnaguha) +- Kedar Kekan (@kedarX) +short_description: Module to configure multiline banners. +description: +- This module will configure both exec and motd banners on remote device running Cisco + IOS XR. It allows playbooks to add or remove banner text from the running configuration. +version_added: 1.0.0 +requirements: +- ncclient >= 0.5.3 when using netconf +- lxml >= 4.1.1 when using netconf +extends_documentation_fragment: +- cisco.iosxr.iosxr +notes: +- This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR + Platform Options,../network/user_guide/platform_iosxr.html). +options: + banner: + description: + - Specifies the type of banner to configure on remote device. + required: true + type: str + choices: + - login + - motd + text: + description: + - Banner text to be configured. Accepts multi line string, without empty lines. + When using a multi line string, the first and last characters must be the + start and end delimiters for the banner + Requires I(state=present). + type: str + state: + description: + - Existential state of the configuration on the device. + default: present + type: str + choices: + - present + - absent +""" + +EXAMPLES = """ +- name: configure the login banner + cisco.iosxr.iosxr_banner: + banner: login + text: | + @this is my login banner + that contains a multiline + string@ + state: present +- name: remove the motd banner + cisco.iosxr.iosxr_banner: + banner: motd + state: absent +- name: Configure banner from file + cisco.iosxr.iosxr_banner: + banner: motd + text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}" + state: present +""" + +RETURN = """ +commands: + description: The list of configuration mode commands sent to device with transport C(cli) + returned: always (empty list when no commands to send) + type: list + sample: + - banner login + - "@this is my login banner" + - that contains a multiline + - string@ + +xml: + description: NetConf rpc xml sent to device with transport C(netconf) + returned: always (empty list when no xml rpc to send) + type: list + sample: + - '<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <banners xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg"> + <banner xc:operation="merge"> + <banner-name>motd</banner-name> + <banner-text>Ansible banner example</banner-text> + </banner> + </banners> + </config>' +""" + +import collections +import re + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + build_xml, + etree_find, + get_config, + is_cliconf, + is_netconf, + load_config, +) + + +class ConfigBase(object): + def __init__(self, module): + self._module = module + self._result = {"changed": False, "warnings": []} + self._want = {} + self._have = {} + + def map_params_to_obj(self): + text = self._module.params["text"] + if text: + text = "{0}".format(str(text).strip()) + self._want.update( + { + "banner": self._module.params["banner"], + "text": text, + "state": self._module.params["state"], + }, + ) + + +class CliConfiguration(ConfigBase): + def __init__(self, module): + super(CliConfiguration, self).__init__(module) + + def map_obj_to_commands(self): + commands = list() + state = self._module.params["state"] + if state == "absent": + if self._have.get("state") != "absent" and ( + "text" in self._have.keys() and self._have["text"] + ): + commands.append("no banner {0!s}".format(self._module.params["banner"])) + elif state == "present": + if self._want["text"] and self._want["text"].encode().decode( + "unicode_escape", + ) != self._have.get("text"): + banner_cmd = "banner {0!s} ".format(self._module.params["banner"]) + banner_cmd += self._want["text"].strip() + commands.append(banner_cmd) + self._result["commands"] = commands + if commands: + commit = not self._module.check_mode + diff = load_config(self._module, commands, commit=commit) + if diff: + self._result["diff"] = dict(prepared=diff) + self._result["changed"] = True + + def map_config_to_obj(self): + cli_filter = "banner {0!s}".format(self._module.params["banner"]) + output = get_config(self._module, config_filter=cli_filter) + match = re.search(r"banner (\S+) (.*)", output, re.DOTALL) + if match: + text = match.group(2) + else: + text = None + obj = {"banner": self._module.params["banner"], "state": "absent"} + if output: + obj["text"] = text + obj["state"] = "present" + self._have.update(obj) + + def run(self): + self.map_params_to_obj() + self.map_config_to_obj() + self.map_obj_to_commands() + + return self._result + + +class NCConfiguration(ConfigBase): + def __init__(self, module): + super(NCConfiguration, self).__init__(module) + self._banners_meta = collections.OrderedDict() + self._banners_meta.update( + [ + ("banner", {"xpath": "banners/banner", "tag": True, "attrib": "operation"}), + ("a:banner", {"xpath": "banner/banner-name"}), + ("a:text", {"xpath": "banner/banner-text", "operation": "edit"}), + ], + ) + + def map_obj_to_xml_rpc(self): + state = self._module.params["state"] + _get_filter = build_xml( + "banners", + xmap=self._banners_meta, + params=self._module.params, + opcode="filter", + ) + + running = get_config(self._module, source="running", config_filter=_get_filter) + + banner_name = None + banner_text = None + if etree_find(running, "banner-text") is not None: + banner_name = etree_find(running, "banner-name").text + banner_text = etree_find(running, "banner-text").text + + opcode = None + if state == "absent" and banner_name == self._module.params["banner"] and len(banner_text): + opcode = "delete" + elif state == "present": + opcode = "merge" + + self._result["xml"] = [] + if opcode: + _edit_filter = build_xml( + "banners", + xmap=self._banners_meta, + params=self._module.params, + opcode=opcode, + ) + + if _edit_filter is not None: + commit = not self._module.check_mode + diff = load_config( + self._module, + _edit_filter, + commit=commit, + running=running, + nc_get_filter=_get_filter, + ) + + if diff: + self._result["xml"] = _edit_filter + if self._module._diff: + self._result["diff"] = dict(prepared=diff) + + self._result["changed"] = True + + def run(self): + self.map_params_to_obj() + self.map_obj_to_xml_rpc() + + return self._result + + +def main(): + """main entry point for module execution""" + argument_spec = dict( + banner=dict(required=True, choices=["login", "motd"]), + text=dict(), + state=dict(default="present", choices=["present", "absent"]), + ) + + required_if = [("state", "present", ("text",))] + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=required_if, + supports_check_mode=True, + ) + + config_object = None + if is_cliconf(module): + # Commenting the below cliconf deprecation support call for Ansible 2.9 as it'll be continued to be supported + config_object = CliConfiguration(module) + elif is_netconf(module): + config_object = NCConfiguration(module) + + result = None + if config_object is not None: + result = config_object.run() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp.py new file mode 100644 index 00000000..9a42225a --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp.py @@ -0,0 +1,365 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_bgp +author: Nilashish Chakraborty (@NilashishC) +short_description: Module to configure BGP protocol settings. +description: +- This module provides configuration management of global BGP parameters on devices + running Cisco IOS-XR +version_added: 1.0.0 +deprecated: + alternative: iosxr_bgp_global + why: Updated module released with more functionality. + removed_at_date: '2023-01-29' +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +options: + config: + description: + - Specifies the BGP related configuration. + type: dict + suboptions: + bgp_as: + description: + - Specifies the BGP Autonomous System (AS) number to configure on the device. + type: int + required: true + router_id: + description: + - Configures the BGP routing process router-id value. + type: str + log_neighbor_changes: + description: + - Enable/disable logging neighbor up/down and reset reason. + type: bool + neighbors: + description: + - Specifies BGP neighbor related configurations. + type: list + elements: dict + suboptions: + neighbor: + description: + - Neighbor router address. + type: str + required: true + remote_as: + description: + - Remote AS of the BGP neighbor to configure. + type: int + required: true + update_source: + description: + - Source of the routing updates. + type: str + password: + description: + - Password to authenticate the BGP peer connection. + type: str + enabled: + description: + - Administratively shutdown or enable a neighbor. + type: bool + description: + description: + - Neighbor specific description. + type: str + advertisement_interval: + description: + - Specifies the minimum interval (in seconds) between sending BGP routing + updates. + - The range is from 0 to 600. + type: int + tcp_mss: + description: + - Specifies the TCP initial maximum segment size to use. + - The range is from 68 to 10000. + type: int + ebgp_multihop: + description: + - Specifies the maximum hop count for EBGP neighbors not on directly connected + networks. + - The range is from 0 to 255. + type: int + timers: + description: + - Specifies BGP neighbor timer related configurations. + type: dict + suboptions: + keepalive: + description: + - Frequency with which the Cisco IOS-XR software sends keepalive messages + to its peer. + - The range is from 0 to 65535. + type: int + holdtime: + description: + - Interval after not receiving a keepalive message that the software + declares a peer dead. + - The range is from 3 to 65535. + type: int + min_neighbor_holdtime: + description: + - Interval specifying the minimum acceptable hold-time from a BGP + neighbor. + - The minimum acceptable hold-time must be less than, or equal to, + the interval specified in the holdtime argument. + - The range is from 3 to 65535. + type: int + address_family: + description: + - Specifies BGP address family related configurations. + type: list + elements: dict + suboptions: + afi: + description: + - Type of address family to configure. + choices: + - ipv4 + - ipv6 + required: true + type: str + safi: + description: + - Specifies the type of cast for the address family. + choices: + - flowspec + - unicast + - multicast + - labeled-unicast + type: str + default: unicast + redistribute: + description: + - Specifies the redistribute information from another routing protocol. + type: list + elements: dict + suboptions: + protocol: + description: + - Specifies the protocol for configuring redistribute information. + type: str + choices: + - ospf + - ospfv3 + - eigrp + - isis + - static + - connected + - lisp + - mobile + - rip + - subscriber + required: true + id: + description: + - Identifier for the routing protocol for configuring redistribute + information. + - Valid for protocols 'ospf', 'eigrp', 'isis' and 'ospfv3'. + type: str + metric: + description: + - Specifies the metric for redistributed routes. + type: int + route_map: + description: + - Specifies the route map reference. + type: str + networks: + description: + - Specify networks to announce via BGP. + - For operation replace, this option is mutually exclusive with root level + networks option. + type: list + elements: dict + suboptions: + network: + description: + - Network ID to announce via BGP. + required: true + aliases: + - prefix + type: str + masklen: + description: + - Subnet mask length for the network to announce(e.g, 8, 16, 24, etc.). + type: int + required: true + route_map: + description: + - Route map to modify the attributes. + type: str + operation: + description: + - Specifies the operation to be performed on the BGP process configured on the + device. + - In case of merge, the input configuration will be merged with the existing BGP + configuration on the device. + - In case of replace, if there is a diff between the existing configuration and + the input configuration, the existing configuration will be replaced by the + input configuration for every option that has the diff. + - In case of override, all the existing BGP configuration will be removed from + the device and replaced with the input configuration. + - In case of delete the existing BGP configuration will be removed from the device. + default: merge + type: str + choices: + - merge + - replace + - override + - delete +""" + +EXAMPLES = """ +- name: configure global bgp as 65000 + cisco.iosxr.iosxr_bgp: + bgp_as: 65000 + router_id: 1.1.1.1 + neighbors: + - neighbor: 182.168.10.1 + remote_as: 500 + description: PEER_1 + - neighbor: 192.168.20.1 + remote_as: 500 + update_source: GigabitEthernet 0/0/0/0 + address_family: + - name: ipv4 + cast: unicast + networks: + - network: 192.168.2.0/23 + - network: 10.0.0.0/8 + redistribute: + - protocol: ospf + id: 400 + metric: 110 + +- name: remove bgp as 65000 from config + ios_bgp: + bgp_as: 65000 + state: absent +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - router bgp 65000 + - bgp router-id 1.1.1.1 + - neighbor 182.168.10.1 remote-as 500 + - neighbor 182.168.10.1 description PEER_1 + - neighbor 192.168.20.1 remote-as 500 + - neighbor 192.168.20.1 update-source GigabitEthernet0/0/0/0 + - address-family ipv4 unicast + - redistribute ospf 400 metric 110 + - network 192.168.2.0/23 + - network 10.0.0.0/8 + - exit +""" +from ansible.module_utils._text import to_text + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.cli.config.bgp.process import ( + REDISTRIBUTE_PROTOCOLS, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.module import ( + NetworkModule, +) + + +def main(): + """main entry point for module execution""" + network_spec = { + "network": dict(aliases=["prefix"], required=True), + "masklen": dict(type="int", required=True), + "route_map": dict(), + } + + redistribute_spec = { + "protocol": dict(choices=REDISTRIBUTE_PROTOCOLS, required=True), + "id": dict(), + "metric": dict(type="int"), + "route_map": dict(), + } + + timer_spec = { + "keepalive": dict(type="int"), + "holdtime": dict(type="int"), + "min_neighbor_holdtime": dict(type="int"), + } + + neighbor_spec = { + "neighbor": dict(required=True), + "remote_as": dict(type="int", required=True), + "update_source": dict(), + "password": dict(no_log=True), + "enabled": dict(type="bool"), + "description": dict(), + "advertisement_interval": dict(type="int"), + "ebgp_multihop": dict(type="int"), + "tcp_mss": dict(type="int"), + "timers": dict(type="dict", options=timer_spec), + } + + address_family_spec = { + "afi": dict(choices=["ipv4", "ipv6"], required=True), + "safi": dict( + choices=["flowspec", "labeled-unicast", "multicast", "unicast"], + default="unicast", + ), + "networks": dict(type="list", elements="dict", options=network_spec), + "redistribute": dict( + type="list", + elements="dict", + options=redistribute_spec, + ), + } + + config_spec = { + "bgp_as": dict(type="int", required=True), + "router_id": dict(), + "log_neighbor_changes": dict(type="bool"), + "neighbors": dict(type="list", elements="dict", options=neighbor_spec), + "address_family": dict( + type="list", + elements="dict", + options=address_family_spec, + ), + } + + argument_spec = { + "config": dict(type="dict", options=config_spec), + "operation": dict( + default="merge", + choices=["merge", "replace", "override", "delete"], + ), + } + + module = NetworkModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + try: + result = module.edit_config(config_filter="router bgp") + except Exception as exc: + module.fail_json(msg=to_text(exc)) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_address_family.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_address_family.py new file mode 100644 index 00000000..3010a2f7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_address_family.py @@ -0,0 +1,945 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_bgp_address_family +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_bgp_address_family +short_description: Resource module to configure BGP Address family. +description: +- This module configures and manages the attributes of BGP address family on Cisco IOS-XR platforms. +version_added: 2.0.0 +author: Ashwini Mhatre (@amhatre) +notes: +- This module works with connection C(network_cli). +options: + config: + description: A list of configurations for BGP address family. + type: dict + suboptions: + as_number: + description: Autonomous system number. + type: str + address_family: + description: Enable address family and enter its config mode + type: list + elements: dict + suboptions: + afi: + description: address family. + type: str + choices: ['ipv4', 'ipv6', 'l2vpn', 'link-state', 'vpnv4', 'vpnv6'] + safi: + description: Address Family modifier + type: str + choices: [ 'flowspec', 'mdt', 'multicast', 'mvpn', 'rt-filter', 'tunnel', 'unicast', 'evpn', 'mspw', 'vpls-vpws', 'link-state' ] + vrf: + description: VRF name. + type: str + additional_paths: &additional_paths + description: BGP additional-paths commands + type: str + choices: [ 'send', 'receive' ] + advertise_best_external: &advertise + description: Advertise best-external path. + type: bool + aggregate_address: + description: Configure BGP aggregate entries. + type: list + elements: dict + suboptions: + value: + type: str + description: IPv4 Aggregate address and mask or masklength. + as_set: + type: bool + description: Generate AS set path information. + as_confed_set: + type: bool + description: Generate AS confed set path information. + summary_only: + type: bool + description: Filter more specific routes from updates. + route_policy: + description: Policy to condition advertisement, suppression, and attributes. + type: str + allocate_label: + type: dict + description: Allocate labels. + suboptions: + all: + type: bool + description: Allocate labels for all prefixes. + route_policy: + description: Use a route policy to select prefixes for label allocation. + type: str + as_path_loopcheck_out_disable: + type: bool + description: Configure AS Path loop checking for outbound updates. + bgp: + type: dict + description: BGP Commands. + suboptions: + attribute_download: &attribute_download + type: bool + description: Configure attribute download for this address-family. + bestpath: + type: dict + description: Change default route selection criteria. + suboptions: + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + use: + description: BGP origin-AS knobs. + type: dict + suboptions: + validity: + description: BGP bestpath selection will use origin-AS validity + type: bool + allow: + description: BGP origin-AS knobs. + type: dict + suboptions: + invalid: + description: BGP bestpath selection will allow 'invalid' origin-AS + type: bool + client_to_client: + type: dict + description: Configure client to client route reflection. + suboptions: + reflection: + type: dict + description: disable client to client reflection of cluster id. + suboptions: + cluster_id_disable: + type: dict + description: ID of Cluster for which reflection is to be disabled. + suboptions: + cluster_id: + type: str + description: ID of Cluster for which reflection is to be disabled. + disable: + type: bool + description: disable cluster id. + disable: + type: bool + description: disable reflection. + dampening: + type: dict + description: Enable route-flap dampening + suboptions: + set: + type: bool + description: Enable dampening. + value: + type: int + description: Half-life time for the penalty + route_policy: + description: Route policy to specify criteria for dampening. + type: str + label_delay: + type: dict + description: Specify delay for batching label processing + suboptions: + delay_second_parts: + type: int + description: Delay, seconds part <0-10>. + delay_ms_parts: + type: int + description: milliseconds part <0-999>. + import_delay: + type: dict + description: Specify delay for batching import processing. + suboptions: + delay_second_parts: + type: int + description: Delay, seconds part <0-10>. + delay_ms_parts: + type: int + description: milliseconds part <0-999>. + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + validation: + description: BGP origin-AS validation knobs. + type: dict + suboptions: + disable: + description: Disable RPKI origin-AS validation. + type: bool + signal: + description: Signal origin-AS validity towards peers. + type: dict + suboptions: + ibgp: + description: Signal origin-AS validity towards iBGP peers + type: bool + scan_time: + description: Configure background scanner interval for this address-family Example- <5-3600>. + type: int + default_martian_check_disable: + type: bool + description: Martian check default + distance: &distance + type: dict + description: Define an administrative distance. + suboptions: + routes_external_to_as: + type: int + description: Distance for routes external to the AS <1-255>. + routes_internal_to_as: + type: int + description: Distance for routes internal to the AS <1-255>. + local_routes: + type: int + description: Distance for local routes <1-255>. + dynamic_med: + type: int + description: Dynamic MED Interval. + maximum_paths: + type: dict + description: Forward packets over multiple paths. + suboptions: + ibgp: + type: dict + description: iBGP-multipath. + suboptions: + max_path_value: + type: int + description: <2-64> Number of paths (limit includes backup path). + order_igp_metric: + description: Order candidate multipaths for selection as per configured number(cisco-support). + type: bool + selective_order_igp_metric: + description: Allow multipaths only from marked neighbors + type: bool + unequal_cost: + type: dict + description: Allow multipaths to have different BGP nexthop IGP metrics. + suboptions: + set: + type: bool + description: set unequal_cost. + order_igp_metric: + description: Order candidate multipaths for selection as per configured number(cisco-support). + type: bool + selective_order_igp_metric: + description: Allow multipaths only from marked neighbors + type: bool + ebgp: + type: dict + description: ebgp-multipath. + suboptions: + max_path_value: + type: int + description: <2-64> Number of paths (limit includes backup path). + order_igp_metric: + description: Order candidate multipaths for selection as per configured number(cisco-support). + type: bool + selective_order_igp_metric: + description: Allow multipaths only from marked neighbors + type: bool + eibgp: + type: dict + description: eiBGP-multipath. + suboptions: + max_path_value: + type: int + description: <2-64> Number of paths (limit includes backup path). + order_igp_metric: + description: Order candidate multipaths for selection as per configured number(cisco-support). + type: bool + selective_order_igp_metric: + description: Allow multipaths only from marked neighbors + type: bool + networks: + type: list + description: Specify a network to announce via BGP. + elements: dict + suboptions: + network: + type: str + description: Specify a network to announce via BGP. + backdoor_route_policy: + type: str + description: Specify a BGP backdoor route. + route_policy: + type: str + description: Route-policy to modify the attributes. + nexthop: + type: dict + description: Nexthop + suboptions: + resolution_prefix_length_minimum: + type: int + description: Set minimum prefix-length for nexthop resolution. + choices: [0,32] + route_policy: + type: str + description: Policy to filter out nexthop notification. + trigger_delay_critical: + description: For critical notification + type: int + trigger_delay_non_critical: + type: int + description: For non critical notification. + optimal_route_reflection: + type: dict + description: Configure optimal-route-reflection group. + suboptions: + group_name: + type: str + description: ORR group name - maximum 32 characters. + primary_address: + type: str + description: IPv4 primary address. + secondary_address: + type: str + description: IPv4 secondary address + permanent_network_route_policy: + type: str + description: Name of the policy. + retain_local_label: + type: int + description: Label retention time in minutes <3-60>. + table_policy: + type: str + description: Configure policy for installation of routes to RIB. + update: + type: dict + description: BGP Update generation configuration. + suboptions: + limit: + type: dict + description: Update limit. + suboptions: + sub_group: + type: dict + description: Update limit for address-family. + suboptions: + ibgp: + type: int + description: Update limit for iBGP sub-groups<1-512. + ebgp: + type: int + description: Update limit for eBGP sub-groups<1-512. + address_family: + type: int + description: Update limit for sub-groups. + wait_install: + type: bool + description: Wait for route install. + redistribute: + type: list + elements: dict + description: Redistribute information from another routing protocol. + suboptions: + protocol: + description: Specifies the protocol for configuring redistribute information. + type: str + choices: + - ospf + - application + - eigrp + - isis + - static + - connected + - lisp + - mobile + - rip + - subscriber + required: true + id: + type: str + description: + - Identifier for the routing protocol for configuring redistribute + information. Example-application name, eigrp/is-is instance name, ospf tag + - Valid for protocols 'ospf', 'eigrp', 'isis' and 'application'. + metric: + description: + - Specifies the metric for redistributed routes. + type: int + route_policy: + description: + - Specifies the route policy reference. + type: str + internal: + type: bool + description: Redistribute EIGRP internal routes.applicable for eigrp. + external: + type: bool + description: Redistribute EIGRP external routes.applicable for eigrp. + level: + type: str + description: + - Redistribute routes from the specified ISIS levels. + - Redistribute ISIS level 1 routes + - Redistribute ISIS level 1 inter-area routes + - Redistribute ISIS level 2 ISIS routes + choices: [ '1', '2', '1-inter-area' ] + nssa_external: + type: bool + description: Redistribute OSPF NSSA external routes.applicable for ospf. + external_ospf: + type: int + description: Redistribute OSPF external routes.applicable for ospf. + choices: [ 1, 2 ] + inter_as_install: + type: bool + description: Install remote mvpn routes in default vrf.This is applicable for mvpn afi. + segmented_multicast: + type: bool + description: Enable segmented multicast.This is applicable for mvpn afi. + global_table_multicast: + type: bool + description: Enable global table multicast. + vrf_all_conf: + type: dict + description: configuration is for all vrfs and its applicable for afi vpn6 and modifier unicast. + suboptions: + source_rt_import_policy: + type: bool + description: Source import route-targets from import-policy. + table_policy: + type: str + description: Configure policy for installation of routes to RIB. + label_mode: + type: dict + description: Label-related configuration. + suboptions: + per_ce: &per_ce + type: bool + description: Set per CE label mode + per_vrf: &per_vrf + type: bool + description: Set per VRF label mode. + route_policy: &route_policy + type: str + description: Use a route policy to select prefixes for label allocation mode. + weight: &wt + type: dict + description: Define or modify weight. + suboptions: + reset_on_import_disable: + type: bool + description: disable reset_on_import. + reset_on_import: + type: bool + description: set reset_on_import. + allow_vpn_default_originate: + type: bool + description: Allow sending default originate route to VPN neighbor. + label_mode: + type: dict + description: label configuration. + suboptions: + per_ce: *per_ce + per_vrf: *per_vrf + route_policy: *route_policy + per_prefix: + type: bool + description: Set per perfix label mode. + mvpn_single_forwarder_selection_all: + type: bool + description: Enable single forwarder selection for all + mvpn_single_forwarder_selection_highest_ip_address: + type: bool + description: Enable single forwarder selection for PE with highest ip address. + route_target_download: + description: Route target RIB installation. + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the Iosxr device by + executing the command B(show running-config router bgp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.2.1 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_address_family: + state: merged + config: + as_number: "65536" + address_family: + - afi: "ipv4" + safi: "unicast" + vrf: vrf1 + dynamic_med: 9 + redistribute: + - protocol: connected + metric: 10 + - afi: "ipv4" + safi: "unicast" + dynamic_med: 10 + redistribute: + - protocol: application + id: test1 + metric: 10 + bgp: + scan_time: 20 + attribute_download: true + advertise_best_external: true + allocate_label: + all: true +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - address-family ipv4 unicast +# - advertise best-external +# - allocate-label all +# - bgp attribute-download +# - bgp scan-time 20 +# - dynamic-med interval 10 +# - redistribute application test1 metric 10 +# - vrf vrf1 +# - address-family ipv4 unicast +# - dynamic-med interval 9 +# - redistribute connected metric 10 +# +# +# after: +# as_number: "65536" +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# vrf: vrf1 +# dynamic_med: 9 +# redistribute: +# - protocol: connected +# metric: 10 +# - afi: "ipv4" +# safi: "unicast" +# dynamic_med: 10 +# redistribute: +# - protocol: application +# id: "test1" +# metric: 10 +# bgp: +# scan_time: 20 +# attribute_download: true +# advertise_best_external: true +# allocate_label: +# all: true +# +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 9 +# redistribute connected metric 10 +# +# Using replaced +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 9 +# redistribute connected metric 10 +# +# +- name: Replace the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_address_family: + state: replaced + config: + as_number: "65536" + address_family: + - afi: "ipv4" + safi: "unicast" + vrf: vrf1 + dynamic_med: 10 +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - vrf vrf1 +# - address-family ipv4 unicast +# - dynamic-med interval 10 +# - no redistribute connected metric 10 +# +# after: +# as_number: "65536" +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# vrf: vrf1 +# dynamic_med: 10 +# - afi: "ipv4" +# safi: "unicast" +# dynamic_med: 10 +# redistribute: +# - protocol: application +# id: "test1" +# metric: 10 +# bgp: +# scan_time: 20 +# attribute_download: true +# advertise_best_external: true +# allocate_label: +# all: true +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 10 +# +# +# Using overridden +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 9 +# redistribute connected metric 10 +# +# +- name: Override the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_address_family: + state: overridden + config: + as_number: "65536" + address_family: + - afi: "ipv4" + safi: "unicast" + vrf: vrf1 + dynamic_med: 10 + +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - no address-family ipv4 unicast +# - vrf vrf1 +# - address-family ipv4 unicast +# - dynamic-med interval 10 +# - no redistribute connected metric 10 +# +# +# after: +# as_number: "65536" +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# vrf: vrf1 +# dynamic_med: 10 +# +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 10 +# +# +# Using deleted +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 9 +# redistribute connected metric 10 +# +# +- name: Delete the provided configuration + cisco.iosxr.iosxr_bgp_address_family: + state: deleted + config: + +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - no address-family ipv4 unicast +# - vrf vrf1 +# - no address-family ipv4 unicast +# +# +# after: +# as_number: "65536" +# +# +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# +# Using rendered +# ------------- +# +- name: rendered state example + cisco.iosxr.iosxr_bgp_address_family: + state: rendered + config: + as_number: "65536" + address_family: + - afi: "ipv4" + safi: "unicast" + vrf: vrf1 + dynamic_med: 9 + redistribute: + - protocol: connected + metric: 10 + - afi: "ipv4" + safi: "unicast" + dynamic_med: 10 + redistribute: + - protocol: application + id: test1 + metric: 10 + bgp: + scan_time: 20 + attribute_download: true + advertise_best_external: true + allocate_label: + all: true +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - address-family ipv4 unicast +# - advertise best-external +# - allocate-label all +# - bgp attribute-download +# - bgp scan-time 20 +# - dynamic-med interval 10 +# - redistribute application test1 metric 10 +# - vrf vrf1 +# - address-family ipv4 unicast +# - dynamic-med interval 9 +# - redistribute connected metric 10 +# +# Using gathered +# ------------- +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_address_family: + state: gathered + config: + as_number: "65536" + address_family: + - afi: "ipv4" + safi: "unicast" + vrf: vrf1 + dynamic_med: 9 + redistribute: + - protocol: connected + metric: 10 + - afi: "ipv4" + safi: "unicast" + dynamic_med: 10 + redistribute: + - protocol: application + id: test1 + metric: 10 + bgp: + scan_time: 20 + attribute_download: true + advertise_best_external: true + allocate_label: + all: true +# gathered: +# as_number: "65536" +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# vrf: vrf1 +# dynamic_med: 9 +# redistribute: +# - protocol: connected +# metric: 10 +# - afi: "ipv4" +# safi: "unicast" +# dynamic_med: 10 +# redistribute: +# - protocol: application +# id: "test1" +# metric: 10 +# bgp: +# scan_time: 20 +# attribute_download: true +# advertise_best_external: true +# allocate_label: +# all: true +# +# Using parsed +# +#parsed.cfg +#------------ +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# advertise best-external +# allocate-label all +# bgp attribute-download +# bgp scan-time 20 +# address-family vpnv4 unicast +# vrf vrf1 +# rd auto +# address-family ipv4 unicast +# dynamic-med interval 9 +# redistribute connected metric 10 +# +- name: Parse externally provided BGP neighbor AF config + cisco.iosxr.iosxr_bgp_address_family: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Task output (redacted) +# ----------------------- +# parsed: +# as_number: "65536" +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# vrf: vrf1 +# dynamic_med: 9 +# redistribute: +# - protocol: connected +# metric: 10 +# - afi: "ipv4" +# safi: "unicast" +# dynamic_med: 10 +# redistribute: +# - protocol: application +# id: "test1" +# metric: 10 +# bgp: +# scan_time: 20 +# attribute_download: true +# advertise_best_external: true +# allocate_label: +# all: true +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_address_family.bgp_address_family import ( + Bgp_address_familyArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.bgp_address_family.bgp_address_family import ( + Bgp_address_family, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_address_familyArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Bgp_address_family(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_global.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_global.py new file mode 100644 index 00000000..bddd8789 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_global.py @@ -0,0 +1,1328 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_bgp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_bgp_global +short_description: Resource module to configure BGP. +description: +- This module configures and manages the attributes of BGP global on Cisco IOS-XR platforms. +version_added: 2.0.0 +author: Ashwini Mhatre (@amhatre) +notes: +- This module works with connection C(network_cli). +options: + config: + description: A list of configurations for BGP global. + type: dict + suboptions: + as_number: + description: Autonomous system number of the router. + type: str + bfd: &bfd + description: Configure BFD parameters. + type: dict + suboptions: + minimum_interval: &min_interval + description: Specifies the BFD session's minimum-interval value for the neighbor. + type: int + multiplier: &multiplier + description: Specifies the BFD session's multiplier value for the neighbor. + type: int + bgp: &bgp + description: BGP parameters. + type: dict + suboptions: + as_path_loopcheck: + description: Enable AS-path loop checking for iBGP peers. + type: bool + auto_policy_soft_reset: &auto_policy_soft_reset + description: Enable automatic soft peer reset on policy reconfiguration. + type: dict + suboptions: + disable: + description: Disable an automatic soft reset of Border Gateway Protocol (BGP) peers. + type: bool + bestpath: &bestpath + description: Select the bestpath selection algorithim for BGP routes. + type: dict + suboptions: + as_path: + description: Select the bestpath selection based on as-path. + type: dict + suboptions: + ignore: + description: ignore + type: bool + multipath_relax: + description: multipath-relax + type: bool + aigp: + description: AIGP attribute + type: dict + suboptions: + ignore: + description: Ignore AIGP attribute. + type: bool + med: + description: MED attribute + type: dict + suboptions: + always: + description: Allow comparing MED from different neighbors. + type: bool + confed: + description: Compare MED among confederation paths. + type: bool + missing_as_worst: + description: Treat missing MED as the least preferred one. + type: bool + compare_routerid: + description: Compare router-id for identical EBGP paths. + type: bool + cost_community: + description: Cost community. + type: dict + suboptions: + ignore: + description: ignore cost_community + type: bool + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + use: + description: BGP origin-AS knobs. + type: dict + suboptions: + validity: + description: BGP bestpath selection will use origin-AS validity + type: bool + allow: + description: BGP origin-AS knobs. + type: dict + suboptions: + invalid: + description: BGP bestpath selection will allow 'invalid' origin-AS + type: bool + cluster_id: &cluster_id + description: Cluster ID of this router acting as a route reflector. + type: str + confederation: &confederation + description: confederation. + type: dict + suboptions: + identifier: + description: Set routing domain confederation AS. + type: int + peers: + description: Enter peer ASs in BGP confederation mode. + type: list + elements: int + default: &default + description: Configure default value. + type: dict + suboptions: + local_preference: + description: + - local preferance. + - Please refer vendor documentation for valid values + type: int + enforce_first_as: &enforce_first_as + description: Enforce the first AS for EBGP routes + type: dict + suboptions: + disable: + description: disable enforce 1st as + type: bool + fast_external_fallover: &fast_external_fallover + description: Immediately reset session if a link to a directly connected external peer goes down. + type: dict + suboptions: + disable: + description: disable fast external fallover. + type: bool + graceful_restart: + description: Enable graceful restart support. + type: dict + suboptions: + set: + description: Enable graceful-restart. + type: bool + graceful_reset: + description: Reset gracefully if configuration change forces a peer reset. + type: bool + restart_time: &restart_time + description: Restart time advertised to neighbors in seconds <1-4095>. + type: int + purge_time: + description: Time before stale routes are purged in seconds <1-6000>. + type: int + stalepath_time: &stalepath_time + description: Maximum time to wait for restart of GR capable peers in seconds <1-4095>. + type: int + install: + description: Install diversion path to RIB/CEF. + type: dict + suboptions: + diversion: + description: Install diversion path to RIB/CEF. + type: bool + log: &bgp_log + description: Log bgp info + type: dict + suboptions: + log_message: + description: Log neighbor inbound/outbound message. + type: dict + suboptions: + disable: + description: disable inbound outbound messages. + type: bool + neighbor: + description: Log neighbor state info. + type: dict + suboptions: + changes: + description: Log neighbor up/down and reset reason. + type: dict + suboptions: + detail: + type: bool + description: detail + disable: + type: bool + description: disable + maximum: + description: Maximum number of neighbors that can be configured + type: dict + suboptions: + neighbor: + description: Maximum number of neighbors <1-15000>. + type: int + multipath: &multipath + description: Change multipath selection criteria + type: dict + suboptions: + as_path: + description: AS path + type: dict + suboptions: + ignore: + description: Ignore as-path related check for multipath selection. + type: dict + suboptions: + onwards: + description: Ignore everything onwards as-path for multipath selection. + type: bool + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + validation: + description: BGP origin-AS validation knobs. + type: dict + suboptions: + disable: + description: Disable RPKI origin-AS validation. + type: bool + signal: + description: Signal origin-AS validity towards peers. + type: dict + suboptions: + ibgp: + description: Signal origin-AS validity towards iBGP peers + type: bool + time: + description: Time to wait between an RPKI update and a BGP table walk. + type: dict + suboptions: + time_off: + description: No automatic prefix validation after an RPKI update. + type: bool + time_in_second: + description: Prefix validation time (in seconds). + type: int + redistribute_internal: &redistribute_internal + description: Redistribute internal BGP routes. + type: bool + router_id: &router_id + description: Configure Router-id. Example- A.B.C.D IPv4 address. + type: str + scan_time: + description: Configure background scanner interval for generic scanner Example- <5-3600>. + type: int + unsafe_ebgp_policy: &ebgp_policy + description: Make eBGP neighbors with no policy pass all routes(cisco-support). + type: bool + update_delay: + description: Set the max initial delay for sending updates Example-<0-3600> in secs. + type: int + default_information: &default_info + description: Control distribution of default information. + type: dict + suboptions: + originate: + description: Distribute a default route + type: bool + default_metric: &default_metric + description: Default metric. Example-<1-4294967295>. + type: int + graceful_maintenance: + description: This allows the router to be brought in or out of service gracefully. + type: dict + suboptions: + activate: + description: All neighbors with graceful-maintenance config + type: str + choices: [ 'all-neighbors','retain-routes','all-neighbors retain-routes', '' ] + ibgp: + description: Set options for iBGP peers. + type: dict + suboptions: + policy: + description: Set options for route-policy. + type: dict + suboptions: + out: + description: Set options for outbound policy. + type: dict + suboptions: + enforce_modifications: + description: Allow policy to modify all attributes. + type: bool + mpls: &mpls + description: Enable mpls parameters. + type: dict + suboptions: + activate: + description: Enter mpls interfaces in BGP mpls activate mode. + type: dict + suboptions: + interface: + description: Name of interface to enable mpls. + type: str + mvpn: + description: Connect to PIM/PIM6. + type: bool + neighbors: &neighbors + description: Specify a neighbor router. + type: list + elements: dict + suboptions: + neighbor_address: + description: + - Neighbor router address. + type: str + aliases: + - neighbor + required: true + advertisement_interval: + description: Minimum interval between sending BGP routing updates.Example-<0-600>. + type: int + bfd: + description: Configure BFD parameters. + type: dict + suboptions: + fast_detect: + description: Enable Fast detection + type: dict + suboptions: + set: + description: set fast-detect + type: bool + disable: + description: Prevent bfd settings from being inherited from the parent. + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + multiplier: *multiplier + minimum_interval: *min_interval + bmp_activate: &bmp_activate + description: Enable BMP logging for this neighbor. + type: dict + suboptions: + server: + description: Enable BMP connection to particular server.Example-<1-8>. + type: int + capability: &capability + description: Advertise capability to the peer. + type: dict + suboptions: + additional_paths: + description: BGP additional-paths commands. + type: dict + suboptions: + send: + type: dict + description: Additional paths Send capability + suboptions: + set: + type: bool + description: set send capability + disable: + type: bool + description: set send capability + receive: + type: dict + description: Additional paths receive capability + suboptions: + set: + type: bool + description: set receive capability + disable: + type: bool + description: set receive capability + suppress: + description: Suppress advertising capability to the peer. + type: dict + suboptions: + four_byte_AS: + description: 4-byte-as capability + type: dict + suboptions: + set: + description: set 4_byte_as. + type: bool + + all: + description: all capability + type: dict + suboptions: + inheritance_disable: + description: Do not inherit this configuration from parent group. + type: bool + set: + description: set all. + type: bool + cluster_id: *cluster_id + description: + description: Neighbor specific description. + type: str + dmz_link_bandwidth: &dmz_link_bw + description: Propagate the DMZ link bandwidth. + type: dict + suboptions: + inheritance_disable: + description: Do not inherit this configuration from parent group. + type: bool + set: + description: set dmz-link-bandwidth. + type: bool + dscp: + description: Set IP DSCP (DiffServ CodePoint).Please refer vendor document for valid entries. + type: str + ebgp_multihop: + description: Allow EBGP neighbors not on directly connected networks. + type: dict + suboptions: + value: + description: maximum hop count.Example-<1-255>. + type: int + mpls: + description: Disable BGP MPLS forwarding. + type: bool + ebgp_recv_extcommunity_dmz: + description: Receive extcommunity dmz link bandwidth from ebgp neighbor. + type: dict + suboptions: + inheritance_disable: + description: Prevent ebgp-recv-community-dmz from being inherited from parent + type: bool + set: + description: set ebgp-recv-community-dmz. + type: bool + ebgp_send_extcommunity_dmz: + description: Send extcommunity dmz link bandwidth from ebgp neighbor. + type: dict + suboptions: + inheritance_disable: + description: Prevent ebgp-send-community-dmz from being inherited from parent + type: bool + cumulatie: + description: Send cumulative community dmz link bandwidth of all multipaths to ebgp neighbor. + type: bool + set: + description: set ebgp-send-community-dmz. + type: bool + egress_engineering: + type: dict + description: Enable egress peer engineering for this neighbor. + suboptions: + inheritance_disable: + description: Prevent egress-engineering from being inherited from parent + type: bool + set: + description: set egress-engineering. + type: bool + enforce_first_as: *enforce_first_as + graceful_maintenance: + description: + Attributes for Graceful Maintenance. This will cause neighbors to de-prefer routes from this router and + choose alternates. This allows the router to be brought in or out of service gracefully. + type: dict + suboptions: + set: + description: set graceful maintenance. + type: bool + activate: + description: Routes will be announced with the graceful maintenance attributes while activated either here or under router + bgp configuration. + type: dict + suboptions: + inheritance_disable: + description: Prevent activate from being inherited from the parent. + type: bool + set: + description: activate. + type: bool + as_prepends: + description: Number of times to prepend the local AS number to the + AS path of routes. Default=0 + type: dict + suboptions: + inheritance_disable: + description: Prevent as prepends from being inherited from the parent. + type: bool + value: + description: Range of values for as prepends.Example-<0-6> . + type: int + local_preference: + description: local preference with which to advertise routes to ibgp neigbors. Default=No Touch + type: dict + suboptions: + value: + description: Range of values for Local Preference.Example-<0-4294967295> . + type: int + inheritance_disable: + description: Prevent local preference from being inherited from the parent. + type: bool + graceful_restart: + description: Enable graceful restart support for this neighbor. + type: dict + suboptions: + restart_time: *restart_time + stalepath_time: *stalepath_time + ignore_connected_check: + description: Bypass the directly connected nexthop check for single-hop eBGP peering + type: dict + suboptions: + inheritance_disable: + description: Prevent ignore-connected-check from being inherited from the parent + type: bool + set: + description: set ignore-connected-check. + type: bool + keychain: + description: Set keychain based authentication. + type: dict + suboptions: + name: + description: Name of the key chain - maximum 32 characters. + type: str + inheritance_disable: + description: Prevent keychain from being inherited from parent. + type: bool + local: + type: dict + description: Configure local parameter + suboptions: + address: + description: IPv4 address + type: dict + suboptions: + ipv4_address: + description: IPv4 address <A.B.C.D>. + type: str + inheritance_disable: + description: Prevent local address from being inherited from parent. + type: bool + local_as: + description: Specify local AS number. + type: dict + suboptions: + value: + description: 2 byte, 4 byte As number + type: int + inheritance_disable: + description: Prevent local AS from being inherited from parent. + type: bool + log: + description: Logging update messages per neighbor. + type: dict + suboptions: + log_message: + description: Logging update/notification messages per neighbor. + type: dict + suboptions: + in: + description: Inbound log messages + type: dict + suboptions: + value: + description: Range for message log buffer size <1-100>. + type: int + disable: + description: Disable inbound message logging. + type: bool + inheritance_disable: + description: Prevents the msg log from being inherited from the parent. + type: bool + out: + description: Outbound log messages + type: dict + suboptions: + value: + description: Range for message log buffer size <1-100>. + type: int + disable: + description: Disable inbound message logging. + type: bool + inheritance_disable: + description: Prevents the msg log from being inherited from the parent. + type: bool + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + validation: + description: BGP origin-AS validation knobs. + type: dict + suboptions: + disable: + description: Disable RPKI origin-AS validation. + type: bool + receive_buffer_size: + description: Set socket and BGP receive buffer size.Example <512-131072>. + type: int + remote_as: + description: Neighbor Autonomous System. + type: int + send_buffer_size: + description: Set socket and BGP send buffer size.Example <4096-131072>. + type: int + session_open_mode: + description: Establish BGP session using this TCP open mode. + type: str + choices: [ 'active-only', 'both', 'passive-only' ] + shutdown: + description: Administratively shut down this neighbor. + type: dict + suboptions: + inheritance_disable: + description: Prevent shutdown from being inherited from parent + type: bool + set: + description: shutdown. + type: bool + tcp: + description: TCP session configuration commands. + type: dict + suboptions: + mss: + description: Maximum Segment Size. + type: dict + suboptions: + value: + description: TCP initial maximum segment size. + type: int + inheritance_disable: + description: Prevent mss from being inherited from parent + type: bool + timers: &timers + description: BGP per neighbor timers. + type: dict + suboptions: + keepalive_time: + description: keepalive interval <0-65535>. + type: int + holdtime: + description: hold time <3-65535> or 0 Disable hold time. + type: int + ttl_security: + description: Enable EBGP TTL security. + type: dict + suboptions: + inheritance_disable: + description: Prevent ttl-security from being inherited from parent + type: bool + set: + description: set ttl-security + type: bool + update: + description: BGP Update configuration. + type: dict + suboptions: + in: + description: Inbound update message handling. + type: dict + suboptions: + filtering: + description: Inbound update message filtering + type: dict + suboptions: + attribute_filter: + description: Attribute-filter configuration. + type: dict + suboptions: + group: + description: Name of group. + type: str + logging: + description: Update filtering syslog message. + type: dict + suboptions: + disable: + description: Disable update filtering syslog message. + type: bool + update_message: + description: Filtered update messages. + type: dict + suboptions: + buffers: + description: Number of buffers to store filtered update messages. + type: int + update_source: + description: Source of routing updates.Refer vendor document for valid values. + type: str + nsr: + description: Enable non-stop-routing support for all neighbors. + type: dict + suboptions: + set: + type: bool + description: set nsr + disable: + type: bool + description: disable nsr + socket: &socket + description: set socket parameters. + type: dict + suboptions: + receive_buffer_size: + description: socket receive buffer size.Example-<512-131072>. + type: int + send_buffer_size: + description: socket send buffer size.Example- <4096-131072>. + type: int + timers: *timers + update: + description: BGP Update configuration. + type: dict + suboptions: + in: + description: Inbound update message handling + type: dict + suboptions: + error_handling: + description: Inbound update message error handling. + type: dict + suboptions: + basic: + description: Inbound update message basic error handling + type: dict + suboptions: + ebgp: + type: dict + description: Inbound update message basic error handling for EBGP neighbors + suboptions: + disable: + description: disable + type: bool + ibgp: + type: dict + description: Inbound update message basic error handling for ibgp neighbors + suboptions: + disable: + description: disable + type: bool + extended: + description: Inbound update message extended error handling + type: dict + suboptions: + ebgp: + type: bool + description: Inbound update message extended error handling for EBGP neighbors + + ibgp: + type: bool + description: Inbound update message extended error handling for ibgp neighbors + out: + description: BGP Update generation configuration. + type: dict + suboptions: + logging: + description: Enable logging of update generation events. + type: bool + limit: + description: Upper bound on transient memory usage for update generation.Example-<16-2048>. + type: int + rpki: + description: Configure RPKI. + type: dict + suboptions: + route: + description: Configure an RPKI route.A.B.C.D/length or X:X::X/length Network/Minimum prefix length + type: dict + suboptions: + value: + description: A.B.C.D/length or X:X::X/length Network/Minimum prefix length. + type: str + max: + description: Maximum prefix length. Example- <1-128> . + type: int + origin: + description: Origin Autonomous System number (in asplain format) Example-<1-4294967295>. + type: int + servers: + description: Configure RPKI cache-servers. + type: list + elements: dict + suboptions: + name: + description: address of rpki server. + type: str + purge_time: + type: int + description: Time to wait after a cache goes down to clean up stale routes + refresh_time: + type: dict + description: Time between sending serial-queries for the RPKI cache-server + suboptions: + value: + description: Purge time (in seconds) <30-360> + type: int + time_off: + description: Do not send serial-queries periodically + type: bool + response_time: + type: dict + description: Time to wait for a response from the RPKI cache-server + suboptions: + value: + description: Purge time (in seconds) <15-3600> + type: int + time_off: + description: Wait indefinitely for a response + type: bool + shutdown: + type: bool + description: Shutdown the RPKI cache-server + transport: + type: dict + description: Specify a transport method for the RPKI cache-server + suboptions: + ssh: + description: Connect to the RPKI cache-server using SSH + type: dict + suboptions: + port: + description: Specify a port number for the RPKI cache-server transport + type: int + tcp: + description: Connect to the RPKI cache-server using TCP (unencrypted) + type: dict + suboptions: + port: + description: Specify a port number for the RPKI cache-server transport + type: int + vrfs: + description: Specify a vrf name. + type: list + elements: dict + suboptions: + vrf: + description: VRF name. + type: str + bfd: *bfd + bgp: + description: BGP commands. + type: dict + suboptions: + auto_policy_soft_reset: *auto_policy_soft_reset + bestpath: *bestpath + default: *default + enforce_first_as: *enforce_first_as + fast_external_fallover: *fast_external_fallover + log: *bgp_log + multipath: *multipath + redistribute_internal: *redistribute_internal + router_id: *router_id + unsafe_ebgp_policy: *ebgp_policy + default_information: *default_info + default_metric: *default_metric + mpls: *mpls + neighbors: *neighbors + rd: + description: route distinguisher. + type: dict + suboptions: + auto: + description: Automatic route distinguisher. + type: bool + socket: *socket + timers: *timers + running_config: + description: + The state the configuration should be left in. + - State I(purged) removes all the BGP configurations from the + target device. Use caution with this state. + - State I(deleted) only removes BGP attributes that this modules + manages and does not negate the BGP process completely. Thereby, preserving + address-family related configurations under BGP context. + - Running states I(deleted) and I(replaced) will result in an error if there + are address-family configuration lines present under a neighbor, + or a vrf context that is to be removed. Please use the + M(cisco.iosxr.iosxr_bgp_address_family) or M(cisco.iosxr.iosxr_bgp_neighbor_address_family) + modules for prior cleanup. + - Refer to examples for more details. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: [deleted, merged, replaced, gathered, rendered, parsed, purged] + default: merged +""" +EXAMPLES = """ + +##### Using Merged ########################################## +----------------------------------------------------------------- + +# configuration on device Before merge state: + + +#RP/0/0/CPU0:10#show running-config router bgp +#Thu Feb 4 09:38:36.245 UTC +#% No such configuration item(s) +#RP/0/0/CPU0:10# + +# --------------Merge state--------------- +# - name: Merge the following configuration +# cisco.iosxr.iosxr_bgp_global: +# config: +# as_number: 65536 +# default_metric: 5 +# socket: +# receive_buffer_size: 514 +# send_buffer_size: 4098 +# bgp: +# confederation: +# identifier: 4 +# bestpath: +# med: +# confed: True +# cluster_id: 5 +# router_id: 192.0.2.10 +# neighbors: +# - neighbor: 192.0.2.13 +# remote_as: 65538 +# bfd: +# fast_detect: +# strict_mode: True +# multiplier: 6 +# minimum_interval: 20 +# vrfs: +# - vrf: vrf1 +# default_metric: 5 +# ---------------------------------------- +# + + +# commands: +# - "router bgp 65536", +# - "bgp cluster-id 5", +# - "bgp router-id 192.0.2.10", +# - "bgp bestpath med confed", +# - "bgp confederation identifier 4", +# - "default-metric 5", +# - "socket receive-buffer-size 514", +# - "socket send-buffer-size 4098", +# - "neighbor 192.0.2.13", +# - "bfd fast-detect strict-mode", +# - "bfd minimum-interval 20", +# - "bfd multiplier 6", +# - "remote-as 65538", +# - "vrf vrf1", +# - "default-metric 5" + +# Configuration on device After Merge state: +# -------------------------------------------- + +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 09:44:32.480 UTC +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 5 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# neighbor 192.0.2.13 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# ! +# vrf vrf1 +# default-metric 5 +# ! +# ! + +##### Using replaced ########################################### + +# configuration on device before replaced +# -------------------------------------------- +# +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 09:44:32.480 UTC +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 5 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# neighbor 192.0.2.13 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# ! +# vrf vrf1 +# default-metric 5 +# ! +# ! +# --------------Replace state--------------- +# - name: Replace the following configuration +# cisco.iosxr.iosxr_bgp_global: +# state: replaced +# config: +# as_number: 65536 +# default_metric: 4 +# socket: +# receive_buffer_size: 514 +# send_buffer_size: 4098 +# bgp: +# confederation: +# identifier: 4 +# bestpath: +# med: +# confed: True +# cluster_id: 5 +# router_id: 192.0.2.10 +# neighbors: +# - neighbor: 192.0.2.14 +# remote_as: 65538 +# bfd: +# fast_detect: +# strict_mode: True +# multiplier: 6 +# minimum_interval: 20 +# vrfs: +# - vrf: vrf1 +# default_metric: 5 +# ------------------------------------------- +# commands: +# - "router bgp 65536", +# - "default-metric 4", +# - "neighbor 192.0.2.14", +# - "bfd fast-detect strict-mode", +# - "bfd minimum-interval 20", +# - "bfd multiplier 6", +# - "remote-as 65538", +# - "no neighbor 192.0.2.13" + +# configuration on device After Replaced state: +# ---------------------------------------------- + +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 09:54:11.161 UTC +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 4 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# neighbor 192.0.2.14 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# ! +# vrf vrf1 +# default-metric 5 +# ! +# ! + + +##### Using deleted ############################################ + +# configuration on device Before deleted state +# --------------------------------------------- +# +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 09:54:11.161 UTC +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 4 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# neighbor 192.0.2.14 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# ! +# vrf vrf1 +# default-metric 5 +# ! +# ! +# +# -------------------------------------------------------- +# - name: Delete BGP configurations handled by this module +# cisco.iosxr.iosxr_bgp_global: +# state: deleted +# config: +# as_number: 65536 +# +# commands: +# "router bgp 65536", +# "no bgp cluster-id 5", +# "no bgp router-id 192.0.2.10", +# "no bgp bestpath med confed", +# "no bgp confederation identifier 4", +# "no default-metric 4", +# "no socket receive-buffer-size 514", +# "no socket send-buffer-size 4098", +# "no neighbor 192.0.2.14", +# "no vrf vrf1" +# +# configuration on device after delete +# ------------------------------------------- +# +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 10:01:08.232 UTC +# router bgp 65536 +# ! +# + + +################# Using Purged ######################################## + +# configuration on device Before Purged state +# -------------------------------------------- +# +# RP/0/0/CPU0:10#show running-config router bgp +# Thu Feb 4 09:54:11.161 UTC +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 4 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# address-family ipv4 unicast +# neighbor 192.0.2.14 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# address-family ipv4 unicast +# ! +# vrf vrf1 +# default-metric 5 +# ! +# ! +# +# - name: Purge all BGP configurations from the device +# cisco.iosxr.iosxr_bgp_global: +# state: purged +# +# commands: +# - no router bgp 65563 +# +# configuration on device After purged state: +# --------------------------------------------- +# +# #RP/0/0/CPU0:10#show running-config router bgp +# #Thu Feb 4 09:38:36.245 UTC +# #% No such configuration item(s) +# #RP/0/0/CPU0:10# +# +# +# ################# Using Rendred ####################################################### +# +# - name: Render platform specific configuration lines (without connecting to the device) +# cisco.iosxr.iosxr_bgp_global: +# state: rendered +# config: +# as_number: 1 +# default_metric: 4 +# vrfs: +# - vrf: vrf3 +# bfd: +# minimum_interval: 20 +# multiplier: 10 +# bgp: +# fast_external_fallover: +# disable: True +# router_id: 1.2.3.4 +# auto_policy_soft_reset: +# disable: True +# #rd: +# # auto: True +# # #value: 1 +# timers: +# keepalive_time: 20 +# holdtime: 30 +# - vrf: vrf2 +# bgp: +# enforce_first_as: +# disable: True +# default_metric: 4 +# neighbors: +# - neighbor: 1.1.1.3 +# remote_as: 2 +# graceful_maintenance: +# set: True +# activate: +# #set: True +# inheritance_disable: True +# local_preference: +# value: 1 +# #inheritance_disable: True +# as_prepends: +# value: 2 +# rendered output +# ------------------------------------ +# "router bgp 1", +# "default-metric 4", +# "vrf vrf3", +# "bfd multiplier 10", +# "bfd minimum-interval 20", +# "bgp auto-policy-soft-reset disable", +# "bgp fast-external-fallover disable", +# "bgp router-id 1.2.3.4", +# "timers bgp 20 30", +# "vrf vrf2", +# "neighbor 1.1.1.3", +# "remote-as 2", +# "graceful-maintenance", +# "graceful-maintenance activate inheritance-disable", +# "graceful-maintenance local-preference 1", +# "graceful-maintenance as-prepends 2", +# "bgp enforce-first-as disable", +# "default-metric 4" +# +# ############## Using parsed ##################### +# parsed.cfg +# ------------ +# router bgp 65536 +# bgp confederation identifier 4 +# bgp router-id 192.0.2.10 +# bgp cluster-id 5 +# default-metric 4 +# socket send-buffer-size 4098 +# bgp bestpath med confed +# socket receive-buffer-size 514 +# neighbor 192.0.2.11 +# remote-as 65537 +# cluster-id 3 +# ! +# neighbor 192.0.2.14 +# remote-as 65538 +# bfd fast-detect strict-mode +# bfd multiplier 6 +# bfd minimum-interval 20 +# ! +# ! +# ------------------------------------ +# +# - name: Parse externally provided BGP config +# cisco.iosxr.iosxr_bgp_global: +# running_config: "{{ lookup('file', 'parsed.cfg') }}" +# state: parsed +# +# #Task output using parsed +# as_number: "65536" +# default_metric: 4 +# socket: +# receive_buffer_size: 514 +# send_buffer_size: 4098 +# bgp: +# confederation: +# identifier: 4 +# bestpath: +# med: +# confed: true +# cluster_id: "5" +# router_id: "192.0.2.10" +# neighbors: +# - neighbor: 192.0.2.11 +# remote_as: 65537 +# cluster_id: "3" +# - neighbor: "192.0.2.14" +# remote_as: 65538 +# bfd: +# fast_detect: +# strict_mode: true +# multiplier: 6 +# minimum_interval: 20 +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_global.bgp_global import ( + Bgp_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.bgp_global.bgp_global import ( + Bgp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Bgp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_neighbor_address_family.py new file mode 100644 index 00000000..85903d30 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_neighbor_address_family.py @@ -0,0 +1,1197 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_bgp_neighbor_address_family +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_bgp_neighbor_address_family +short_description: Resource module to configure BGP Neighbor Address family. +description: +- This module configures and manages the attributes of BGP global on Cisco IOS-XR platforms. +version_added: 2.0.0 +author: Ashwini Mhatre (@amhatre) +notes: +- This module works with connection C(network_cli). +options: + config: + description: BGP neighbor address family configurations. + type: dict + suboptions: + as_number: + description: Autonomous system number. + type: str + neighbors: + description: A list of BGP neighbor address family configurations. + type: list + elements: dict + suboptions: + neighbor_address: + description: + - Neighbor router address. + type: str + required: true + address_family: + description: Enable address family and enter its config mode + type: list + elements: dict + suboptions: + afi: + description: address family. + type: str + choices: [ 'ipv4', 'ipv6', 'l2vpn', 'link-state', 'vpnv4', 'vpnv6'] + safi: + description: Address Family modifier + type: str + choices: [ 'flowspec', 'mdt', 'multicast', 'mvpn', 'rt-filter', 'tunnel', 'unicast', 'labeled-unicast' ] + aigp: &aigp + description: AIGP attribute + type: dict + suboptions: + disable: + description: Ignore AIGP attribute. + type: bool + set: + description: Set AIGP attribute. + type: bool + send_cost_community_disable: + description: send AIGP attribute. + type: bool + send_med: + description: send med options. + type: dict + suboptions: + set: + type: bool + description: set Send AIGP value in MED. + disable: + description: disable Send AIGP value in MED. + type: bool + allowas_in: &allowas_in + type: dict + description: Allow as-path with my AS present in it. + suboptions: + value: + type: int + description: Number of occurences of AS number 1-10. + set: + type: bool + description: set allowas_in + as_override: &as_override + type: dict + description: Override matching AS-number while sending update + suboptions: + set: + type: bool + description: set as_override + inheritance_disable: + type: bool + description: Prevent as-override from being inherited from the parent. + bestpath_origin_as_allow_invalid: + type: bool + description: Change default route selection criteria.Allow BGP origin-AS knobs. + capability_orf_prefix: &capability + type: str + description: Advertise address prefix ORF capability to this neighbor. + choices: ['both', 'send', 'none', 'receive'] + default_originate: &default_originate + type: dict + description: Originate default route to this neighbor. + suboptions: + set: + type: bool + description: set default route. + route_policy: + type: str + description: Route policy to specify criteria to originate default + inheritance_disable: + type: bool + description: Prevent default-originate from being inherited from the parent. + long_lived_graceful_restart: &long_lived_graceful_restart + type: dict + description: Enable long lived graceful restart support. + suboptions: + capable: + type: bool + description: Treat neighbor as LLGR capable. + stale_time: + type: dict + description: Maximum time to wait before purging long-lived stale routes. + suboptions: + send: + type: int + description: max send time + accept: + type: int + description: max accept time + maximum_prefix: &maximum_prefix + type: dict + description: Maximum number of prefixes to accept from this peer. + suboptions: + max_limit: + type: int + description: maximum no. of prefix limit.<1-4294967295. + threshold_value: + type: int + description: hreshold value (%) at which to generate a warning msg <1-100>. + restart: + type: int + description: Restart time interval. + warning_only: + type: bool + description: Only give warning message when limit is exceeded. + discard_extra_paths: + description: Discard extra paths when limit is exceeded. + type: bool + multipath: &multipath + type: bool + description: Paths from this neighbor is eligible for multipath. + next_hop_self: &next_hop_self + type: dict + description: Disable the next hop calculation for this neighbor. + suboptions: + set: + type: bool + description: set next hop self. + inheritance_disable: + type: bool + description: Prevent next_hop_self from being inherited from the parent. + next_hop_unchanged: &next_hop_unchanged + type: dict + description: Disable the next hop calculation for this neighbor. + suboptions: + set: + type: bool + description: set next hop unchanged. + inheritance_disable: + type: bool + description: Prevent next_hop_unchanged from being inherited from the parent. + multipath: + type: bool + description: Do not overwrite nexthop before advertising multipaths. + optimal_route_reflection_group_name: &optimal_route_reflection + type: str + description: Configure optimal-route-reflection group. + orf_route_policy: &orf_rp + type: str + description: Specify ORF and inbound filtering criteria.' + origin_as: + description: BGP origin-AS knobs. + type: dict + suboptions: + validation: + description: BGP origin-AS validation knobs. + type: dict + suboptions: + disable: + description: Disable RPKI origin-AS validation. + type: bool + remove_private_AS: &remove_private_AS + type: dict + description: Remove private AS number from outbound updates. + suboptions: + set: + type: bool + description: set remove private As. + inbound: + type: bool + description: Remove private AS number from inbound updates. + entire_aspath: + type: bool + description: remove only if all ASes in the path are private. + inheritance_disable: + type: bool + description: Prevent remove-private-AS from being inherited from the parent. + route_policy: &route_policy + type: dict + description: Apply route policy to neighbor. + suboptions: + inbound: + type: str + description: Apply route policy to inbound routes. + outbound: + type: str + description: Apply route policy to outbound routes. + route_reflector_client: &route_reflector_client + type: dict + description: Configure a neighbor as Route Reflector client. + suboptions: + set: + type: bool + description: set route-reflector-client. + inheritance_disable: + type: bool + description: Prevent route-reflector-client from being inherited from the parent. + send_community_ebgp: &send_community_ebgp + description: Send community attribute to this external neighbor. + type: dict + suboptions: + set: + type: bool + description: set send_community_ebgp. + inheritance_disable: + type: bool + description: Prevent send_community_ebgp from being inherited from the parent. + send_community_gshut_ebgp: &send_community_gshut_ebgp + description: Allow the g-shut community to be sent to this external neighbor. + type: dict + suboptions: + set: + type: bool + description: set send_community_gshut_ebgp. + inheritance_disable: + type: bool + description: Prevent send_community_gshut_ebgp from being inherited from the parent. + send_extended_community_ebgp: &send_extended_community_ebgp + description: Send extended community attribute to this external neighbor. + type: dict + suboptions: + set: + type: bool + description: set send_extended_community_ebgp. + inheritance_disable: + type: bool + description: Prevent send_extended_community_ebgp from being inherited from the parent. + send_multicast_attributes: + description: Send multicast attributes to this neighbor . + type: dict + suboptions: + set: + type: bool + description: set send_multicast_attributes. + disable: + type: bool + description: Disable send multicast attributes. + soft_reconfiguration: &soft_reconfiguration + description: Per neighbor soft reconfiguration. + type: dict + suboptions: + inbound: + type: dict + description: inbound soft reconfiguration + suboptions: + set: + type: bool + description: set inbound + always: + type: bool + description: Allow inbound soft reconfiguration for this neighbor. Always use soft reconfig, even if route refresh is supported. + inheritance_disable: + type: bool + description: Prevent soft_reconfiguration from being inherited from the parent. + weight: &wt + type: int + description: Set default weight for routes from this neighbor. + validation: &validation + type: dict + description: Flowspec Validation for this neighbor. + suboptions: + set: + type: bool + description: set validation. + redirect: + type: bool + description: Flowspec Redirect nexthop Validation. + disable: + type: bool + description: disable validation. + vrfs: + description: Configure BGP neighbor afin a VRF. + type: list + elements: dict + suboptions: + vrf: + description: VRF name. + type: str + neighbors: + description: A list of BGP neighbor address family configurations. + type: list + elements: dict + suboptions: + neighbor_address: + description: + - Neighbor router address. + type: str + required: true + address_family: + description: Enable address family and enter its config mode + type: list + elements: dict + suboptions: + afi: + description: address family. + type: str + choices: [ 'ipv4', 'ipv6'] + safi: + description: Address Family modifier + type: str + choices: [ 'flowspec', 'multicast', 'mvpn', 'unicast', 'labeled-unicast' ] + aigp: *aigp + allowas_in: *allowas_in + as_override: + type: dict + description: Override matching AS-number while sending update + aliases: + - as_overrride + suboptions: + set: + type: bool + description: set as_override + inheritance_disable: + type: bool + description: Prevent as-override from being inherited from the parent. + capability_orf_prefix: *capability + default_originate: *default_originate + long_lived_graceful_restart: *long_lived_graceful_restart + maximum_prefix: *maximum_prefix + multipath: *multipath + next_hop_self: *next_hop_self + next_hop_unchanged: *next_hop_unchanged + optimal_route_reflection_group_name: *optimal_route_reflection + orf_route_policy: *orf_rp + remove_private_AS: *remove_private_AS + route_policy: *route_policy + route_reflector_client: *route_reflector_client + send_community_ebgp: *send_community_ebgp + send_community_gshut_ebgp: *send_community_gshut_ebgp + send_extended_community_ebgp: *send_extended_community_ebgp + soft_reconfiguration: *soft_reconfiguration + site_of_origin: + description: Site-of-Origin extended community associated with the neighbor. + type: str + weight: *wt + validation: *validation + + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the Iosxr device by + executing the command B(show running-config router bgp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged +""" +EXAMPLES = """ +# Using merged +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.2.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# neighbor 192.0.2.3 +# remote-as 65538 +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 + +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_neighbor_address_family: + state: merged + config: + as_number: 65536 + neighbors: + - neighbor_address: 192.0.2.2 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 5 + - neighbor_address: 192.0.2.3 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 4 + vrfs: + - vrf: vrf1 + neighbors: + - neighbor_address: 192.0.2.4 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + capability_orf_prefix: both + - vrf: vrf2 + neighbors: + - neighbor_address: 192.0.2.5 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + capability_orf_prefix: both +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - neighbor 192.0.2.2 +# - address-family ipv4 unicast +# - default-originate +# - multipath +# - weight 5 +# - neighbor 192.0.2.3 +# - address-family ipv4 unicast +# - default-originate +# - multipath +# - weight 4 +# - vrf vrf1 +# - neighbor 192.0.2.4 +# - address-family ipv4 unicast +# - capability orf prefix both +# - default-originate +# - multipath +# - vrf vrf2 +# - neighbor 192.0.2.5 +# - address-family ipv4 unicast +# - capability orf prefix both +# - default-originate +# - multipath +# +# +# after: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.2 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 5 +# - neighbor_address: 192.0.2.3 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 4 +# vrfs: +# - vrf: vrf1 +# neighbors: +# - neighbor_address: 192.0.2.4 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# - vrf: vrf2 +# neighbors: +# - neighbor_address: 192.0.2.5 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# +# +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 1.1.1.2 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# +# +# Using delete +# Before state: +# ------------- +# +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 192.0.2.3 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate + +- name: Delete the provided configuration + cisco.iosxr.iosxr_bgp_neighbor_address_family: + state: deleted + config: + as_number: 65536 + neighbors: + - neighbor_address: 192.0.2.2 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 5 + +# Task output +# ------------- +# +# commands: +# - router bgp 65536 +# - neighbor 192.0.2.2 +# - no address-family ipv4 unicast +# +# +# after: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.3 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 4 +# vrfs: +# - vrf: vrf1 +# neighbors: +# - neighbor_address: 192.0.2.4 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# - neighbor_address: 192.0.2.5 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# +# +# Using Replaced +# Before state: +# ------------- +# +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 192.0.2.3 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate + +- name: Replace the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_neighbor_address_family: + state: replaced + config: + as_number: 65536 + neighbors: + - neighbor_address: 192.0.2.2 + address_family: + - afi: "ipv4" + safi: "unicast" + default_originate: + set: true + weight: 4 +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - neighbor 192.0.2.2 +# - address-family ipv4 unicast +# - no multipath +# - weight 4 +# +# after: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.2 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 4 +# - neighbor_address: 192.0.2.3 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 5 +# vrfs: +# - vrf: vrf1 +# neighbors: +# - neighbor_address: 192.0.2.4 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# - neighbor_address: 192.0.2.5 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# +# After state: +# ------------- +# Nexus9000v# show running-config router bgp +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 4 +# default-originate +# neighbor 192.0.2.3 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# +# +# Using overridden +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 192.0.2.3 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate + +- name: override the provided configuration + cisco.iosxr.iosxr_bgp_neighbor_address_family: + state: overridden + config: + as_number: 65536 + neighbors: + - neighbor_address: 192.0.2.2 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 5 +# Task output +# ------------- +# +# commands: +# - router bgp 65536 +# - neighbor 192.0.2.3 +# - no address-family ipv4 unicast +# - vrf vrf1 +# - neighbor 192.0.2.4 +# - no address-family ipv4 unicast +# - vrf vrf1 +# - neighbor 192.0.2.5 +# - no address-family ipv4 unicast +# +# +# +# after: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.2 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 5 +# +# After state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# +# +# +# Using rendered +# Before state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.2.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# neighbor 192.0.2.3 +# remote-as 65538 +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 + +- name: Render platform specific configuration lines with state rendered (without connecting to the device) + cisco.iosxr.iosxr_bgp_neighbor_address_family: + state: rendered + config: + as_number: 65536 + neighbors: + - neighbor_address: 192.0.2.2 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 5 + - neighbor_address: 192.0.2.3 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + weight: 4 + vrfs: + - vrf: vrf1 + neighbors: + - neighbor_address: 192.0.2.4 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + capability_orf_prefix: both + - vrf: vrf2 + neighbors: + - neighbor_address: 192.0.2.5 + address_family: + - afi: "ipv4" + safi: "unicast" + multipath: true + default_originate: + set: true + capability_orf_prefix: both +# Task output +# ------------- +# commands: +# - router bgp 65536 +# - neighbor 192.0.2.2 +# - address-family ipv4 unicast +# - default-originate +# - multipath +# - weight 5 +# - neighbor 192.0.2.3 +# - address-family ipv4 unicast +# - default-originate +# - multipath +# - weight 4 +# - vrf vrf1 +# - neighbor 192.0.2.4 +# - address-family ipv4 unicast +# - capability orf prefix both +# - default-originate +# - multipath +# - vrf vrf2 +# - neighbor 192.0.2.5 +# - address-family ipv4 unicast +# - capability orf prefix both +# - default-originate +# - multipath +# +# Using parsed +# +#parsed.cfg +#------------ +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 1.1.1.2 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate + +- name: Parse externally provided BGP neighbor AF config + cisco.iosxr.iosxr_bgp_neighbor_address_family: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed +# Task output (redacted) +# ----------------------- +# parsed: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.2 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 5 +# - neighbor_address: 192.0.2.3 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 4 +# vrfs: +# - vrf: vrf1 +# neighbors: +# - neighbor_address: 192.0.2.4 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# - vrf: vrf2 +# neighbors: +# - neighbor_address: 192.0.2.5 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# +# +#Using Gathered +#----------------- +# Before state state: +# ------------- +# RP/0/0/CPU0:iosxr-02#show running-config router bgp +# Sat Feb 20 03:49:43.618 UTC +# router bgp 65536 +# bgp router-id 192.0.1.1 +# address-family ipv4 unicast +# address-family vpnv4 unicast +# neighbor 192.0.2.2 +# remote-as 65537 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# neighbor 1.1.1.2 +# remote-as 65538 +# address-family ipv4 unicast +# multipath +# weight 5 +# default-originate +# vrf vrf1 +# rd auto +# neighbor 192.0.2.4 +# remote-as 65539 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# vrf vrf2 +# rd auto +# neighbor 192.0.2.5 +# remote-as 65540 +# address-family ipv4 unicast +# multipath +# capability orf prefix both +# default-originate +# +# +# +- name: Gathered the provided configuration with the existing running configuration + cisco.iosxr.iosxr_bgp_neighbor_address_family: + config: + state: gathered + + +# Task output +# ----------------------- +# gathered: +# as_number: 65536 +# neighbors: +# - neighbor_address: 192.0.2.2 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 5 +# - neighbor_address: 192.0.2.3 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# weight: 4 +# vrfs: +# - vrf: vrf1 +# neighbors: +# - neighbor_address: 192.0.2.4 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# - vrf: vrf2 +# neighbors: +# - neighbor_address: 192.0.2.5 +# address_family: +# - afi: "ipv4" +# safi: "unicast" +# multipath: true +# default_originate: +# set: true +# capability_orf_prefix: both +# + +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.bgp_neighbor_address_family.bgp_neighbor_address_family import ( + Bgp_neighbor_address_familyArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.bgp_neighbor_address_family.bgp_neighbor_address_family import ( + Bgp_neighbor_address_family, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Bgp_neighbor_address_familyArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Bgp_neighbor_address_family(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_command.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_command.py new file mode 100644 index 00000000..5838de0d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_command.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_command +author: Ricardo Carrillo Cruz (@rcarrillocruz) +short_description: Module to run commands on remote devices. +description: +- Sends arbitrary commands to an IOS XR node and returns the results read from the + device. This module includes an argument that will cause the module to wait for + a specific condition before returning or timing out if the condition is not met. +- This module does not support running commands in configuration mode. Please use + M(cisco.iosxr.iosxr_config) to configure iosxr devices. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.iosxr.iosxr +notes: +- Make sure the user has been authorized to execute commands terminal length 0, terminal + width 512 and terminal exec prompt no-timestamp. +- This module works with C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +- This module does not support C(netconf) connection. +options: + commands: + description: + - List of commands to send to the remote iosxr device over the configured provider. + The resulting output from the command is returned. If the I(wait_for) argument + is provided, the module is not returned until the condition is satisfied or + the number of retries has expired. + - If a command sent to the device requires answering a prompt, it is possible to pass + a dict containing command, answer and prompt. Common answers are 'y' or "\\r" + (carriage return, must be double quotes). See examples + type: list + elements: raw + required: true + wait_for: + description: + - List of conditions to evaluate against the output of the command. The task will + wait for each condition to be true before moving forward. If the conditional + is not true within the configured number of retries, the task fails. See examples. + aliases: + - waitfor + type: list + elements: str + match: + description: + - The I(match) argument is used in conjunction with the I(wait_for) argument to + specify the match policy. Valid values are C(all) or C(any). If the value + is set to C(all) then all conditionals in the wait_for must be satisfied. If + the value is set to C(any) then only one of the values must be satisfied. + default: all + choices: + - any + - all + type: str + retries: + description: + - Specifies the number of retries a command should by tried before it is considered + failed. The command is run on the target device every retry and evaluated against + the I(wait_for) conditions. + default: 10 + type: int + interval: + description: + - Configures the interval in seconds to wait between retries of the command. If + the command does not pass the specified conditions, the interval indicates how + long to wait before trying the command again. + default: 1 + type: int +""" + +EXAMPLES = """ +- name: run show version on remote devices + cisco.iosxr.iosxr_command: + commands: show version + +- name: run show version and check to see if output contains iosxr + cisco.iosxr.iosxr_command: + commands: show version + wait_for: result[0] contains IOS-XR + +- name: run multiple commands on remote nodes + cisco.iosxr.iosxr_command: + commands: + - show version + - show interfaces + - {command: example command that prompts, prompt: expected prompt, answer: yes} + +- name: run multiple commands and evaluate the output + cisco.iosxr.iosxr_command: + commands: + - show version + - show interfaces + wait_for: + - result[0] contains IOS-XR + - result[1] contains Loopback0 + +- name: multiple prompt, multiple answer (mandatory check for all prompts) + cisco.iosxr.iosxr_command: + commands: + - command: key config-key password-encryption + prompt: + - "Enter old key :" + - "Enter new key :" + - "Enter confirm key :" + answer: + - "test1234" + - "test12345" + - "test12345" + check_all: true +""" + +RETURN = """ +stdout: + description: The set of responses from the commands + returned: always apart from low level errors (such as action plugin) + type: list + sample: ['...', '...'] +stdout_lines: + description: The value of stdout split into a list + returned: always apart from low level errors (such as action plugin) + type: list + sample: [['...', '...'], ['...'], ['...']] +failed_conditions: + description: The list of conditionals that have failed + returned: failed + type: list + sample: ['...', '...'] +""" +import time + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import ( + Conditional, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_lines + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import run_commands + + +def parse_commands(module, warnings): + commands = module.params["commands"] + for item in list(commands): + try: + command = item["command"] + except Exception: + command = item + if module.check_mode and not command.startswith("show"): + warnings.append( + "Only show commands are supported when using check mode, not " + "executing %s" % command, + ) + commands.remove(item) + + return commands + + +def main(): + argument_spec = dict( + commands=dict(type="list", required=True, elements="raw"), + wait_for=dict(type="list", aliases=["waitfor"], elements="str"), + match=dict(default="all", choices=["all", "any"]), + retries=dict(default=10, type="int"), + interval=dict(default=1, type="int"), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + warnings = list() + result = {"changed": False, "warnings": warnings} + commands = parse_commands(module, warnings) + wait_for = module.params["wait_for"] or list() + + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError as exc: + module.fail_json(msg=to_text(exc)) + + retries = module.params["retries"] + interval = module.params["interval"] + match = module.params["match"] + + while retries > 0: + responses = run_commands(module, commands) + + for item in list(conditionals): + if item(responses): + if match == "any": + conditionals = list() + break + conditionals.remove(item) + + if not conditionals: + break + + time.sleep(interval) + retries -= 1 + + if conditionals: + failed_conditions = [item.raw for item in conditionals] + msg = "One or more conditional statements have not been satisfied" + module.fail_json(msg=msg, failed_conditions=failed_conditions) + + result.update({"stdout": responses, "stdout_lines": list(to_lines(responses))}) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_config.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_config.py new file mode 100644 index 00000000..f723b569 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_config.py @@ -0,0 +1,489 @@ +#!/usr/bin/python +# +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_config +author: Ricardo Carrillo Cruz (@rcarrillocruz) +short_description: Module to manage configuration sections. +description: +- Cisco IOS XR configurations use a simple block indent file syntax for segmenting + configuration into sections. This module provides an implementation for working + with IOS XR configuration sections in a deterministic way. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.iosxr.iosxr +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +- This module does not support C(netconf) connection +- Abbreviated commands are NOT idempotent, see L(Network FAQ,../network/user_guide/faq.html + #why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands). +- Avoid service disrupting changes (viz. Management IP) from config replace. +- Do not use C(end) in the replace config file. +- To ensure idempotency and correct diff the configuration lines in the relevant module options should be similar to how they + appear if present in the running configuration on device including the indentation. +options: + lines: + description: + - The ordered set of commands that should be configured in the section. The commands + must be the exact same commands as found in the device running-config as found in the + device running-config to ensure idempotency and correct diff. Be sure to note the + configuration command syntax as some commands are automatically modified by the + device config parser. + type: list + elements: str + aliases: + - commands + parents: + description: + - The ordered set of parents that uniquely identify the section or hierarchy the + commands should be checked against. If the parents argument is omitted, the + commands are checked against the set of top level or global commands. + type: list + elements: str + src: + description: + - Specifies the source path to the file that contains the configuration or configuration + template to load. The path to the source file can either be the full path on + the Ansible control host or a relative path from the playbook or role root directory. This + argument is mutually exclusive with I(lines), I(parents). The configuration lines in the + source file should be similar to how it will appear if present in the running-configuration + of the device to ensure idempotency and correct diff. + type: path + before: + description: + - The ordered set of commands to push on to the command stack if a change needs + to be made. This allows the playbook designer the opportunity to perform configuration + commands prior to pushing any changes without affecting how the set of commands + are matched against the system. + type: list + elements: str + after: + description: + - The ordered set of commands to append to the end of the command stack if a change + needs to be made. Just like with I(before) this allows the playbook designer + to append a set of commands to be executed after the command set. + type: list + elements: str + match: + description: + - Instructs the module on the way to perform the matching of the set of commands + against the current device config. If match is set to I(line), commands are + matched line by line. If match is set to I(strict), command lines are matched + with respect to position. If match is set to I(exact), command lines must be + an equal match. Finally, if match is set to I(none), the module will not attempt + to compare the source configuration with the running configuration on the remote + device. + type: str + default: line + choices: + - line + - strict + - exact + - none + replace: + description: + - Instructs the module on the way to perform the configuration on the device. If + the replace argument is set to I(line) then the modified lines are pushed to + the device in configuration mode. If the replace argument is set to I(block) + then the entire command block is pushed to the device in configuration mode + if any line is not correct. + type: str + default: line + choices: + - line + - block + - config + force: + description: + - The force argument instructs the module to not consider the current devices + running-config. When set to true, this will cause the module to push the contents + of I(src) into the device without first checking if already configured. + - Note this argument should be considered deprecated. To achieve the equivalent, + set the C(match=none) which is idempotent. This argument will be removed in + a future release. + type: bool + default: no + 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(config) argument allows the implementer + to pass in the configuration to use as the base config for comparison. + The configuration lines for this option should be similar to how it will appear if present + in the running-configuration of the device to ensure idempotency and correct diff. + type: str + backup: + description: + - This argument will cause the module to create a full backup of the current C(running-config) + from the remote device before any changes are made. If the C(backup_options) + value is not given, the backup file is written to the C(backup) folder in the + playbook root directory or role root directory, if playbook is part of an ansible + role. If the directory does not exist, it is created. + type: bool + default: no + comment: + description: + - Allows a commit description to be specified to be included when the configuration + is committed. If the configuration is not changed or committed, this argument + is ignored. + type: str + default: configured by iosxr_config + admin: + description: + - Enters into administration configuration mode for making config changes to the + device. + type: bool + default: no + label: + description: + - Allows a commit label to be specified to be included when the configuration + is committed. A valid label must begin with an alphabet and not exceed 30 characters, + only alphabets, digits, hyphens and underscores are allowed. If the configuration + is not changed or committed, this argument is ignored. + type: str + backup_options: + description: + - This is a dict object containing configurable options related to backup file + path. The value of this option is read only when C(backup) is set to I(yes), + if C(backup) is set to I(no) this option will be silently ignored. + suboptions: + filename: + description: + - The filename to be used to store the backup configuration. If the filename + is not given it will be generated based on the hostname, current time and + date in format defined by <hostname>_config.<current-date>@<current-time> + type: str + dir_path: + description: + - This option provides the path ending with directory name in which the backup + configuration file will be stored. If the directory does not exist it will + be first created and the filename is either the value of C(filename) or + default filename as described in C(filename) options description. If the + path value is not given in that case a I(backup) directory will be created + in the current working directory and backup configuration will be copied + in C(filename) within I(backup) directory. + type: path + type: dict + exclusive: + description: + - Enters into exclusive configuration mode that locks out all users from committing + configuration changes until the exclusive session ends. + type: bool + default: false + disable_default_comment: + description: + - disable default comment when set to True. + type: bool + default: false +""" + +EXAMPLES = """ +- name: configure top level configuration + cisco.iosxr.iosxr_config: + lines: hostname {{ inventory_hostname }} + +- name: configure interface settings + cisco.iosxr.iosxr_config: + lines: + - description test interface + - ip address 172.31.1.1 255.255.255.0 + parents: interface GigabitEthernet0/0/0/0 + +- name: load a config from disk and replace the current config + cisco.iosxr.iosxr_config: + src: config.cfg + replace: config + backup: yes + +- name: for idempotency, use full-form commands + cisco.iosxr.iosxr_config: + lines: + # - shut + - shutdown + # parents: int g0/0/0/1 + parents: interface GigabitEthernet0/0/0/1 + +- name: configurable backup path + cisco.iosxr.iosxr_config: + src: config.cfg + backup: yes + backup_options: + filename: backup.cfg + dir_path: /home/user +""" + +RETURN = """ +commands: + description: The set of commands that will be pushed to the remote device + returned: If there are commands to run against the host + type: list + sample: ['hostname foo', 'router ospf 1', 'router-id 1.1.1.1'] +backup_path: + description: The full path to the backup file + returned: when backup is yes + type: str + sample: /playbooks/ansible/backup/iosxr01_config.2016-07-16@22:28:34 +filename: + description: The name of the backup file + returned: when backup is yes and filename is not specified in backup options + type: str + sample: iosxr01_config.2016-07-16@22:28:34 +shortname: + description: The full path to the backup file excluding the timestamp + returned: when backup is yes and filename is not specified in backup options + type: str + sample: /playbooks/ansible/backup/iosxr01_config +date: + description: The date extracted from the backup file name + returned: when backup is yes + type: str + sample: "2016-07-16" +time: + description: The time extracted from the backup file name + returned: when backup is yes + type: str + sample: "22:28:34" +""" +import os +import re +import tempfile + +from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.connection import ConnectionError +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import ( + NetworkConfig, + dumps, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + copy_file, + get_config, + get_connection, + load_config, +) + + +DEFAULT_COMMIT_COMMENT = "configured by iosxr_config" + + +def copy_file_to_node(module): + """Copy config file to IOS-XR node. We use SFTP because older IOS-XR versions don't handle SCP very well.""" + file = tempfile.NamedTemporaryFile("wb", delete=False) + src = os.path.realpath(file.name) + file.write(to_bytes(module.params["src"], errors="surrogate_or_strict")) + file.close() + + dst = "/harddisk:/ansible_config.txt" + copy_file(module, src, dst, "sftp") + + os.remove(src) + + return True + + +def check_args(module, warnings): + if module.params["comment"]: + if len(module.params["comment"]) > 60: + module.fail_json(msg="comment argument cannot be more than 60 characters") + if module.params["label"]: + label = module.params["label"] + if len(label) > 30: + module.fail_json(msg="label argument cannot be more than 30 characters") + if not label[0].isalpha(): + module.fail_json(msg="label argument must begin with an alphabet") + valid_chars = re.match(r"[\w-]*$", label) + if not valid_chars: + module.fail_json( + msg="label argument must only contain alphabets," + + "digits, underscores or hyphens", + ) + if module.params["force"]: + warnings.append( + "The force argument is deprecated, please use " + "match=none instead. This argument will be " + "removed in the future", + ) + + +def get_running_config(module): + contents = module.params["config"] + if not contents: + contents = get_config(module) + return contents + + +def get_candidate(module): + candidate = "" + if module.params["src"]: + candidate = module.params["src"] + elif module.params["lines"]: + candidate_obj = NetworkConfig(indent=1, comment_tokens=["!"]) + parents = module.params["parents"] or list() + candidate_obj.add(module.params["lines"], parents=parents) + candidate = dumps(candidate_obj, "raw") + return candidate + + +def run(module, result): + match = module.params["match"] + replace = module.params["replace"] + replace_config = replace == "config" + path = module.params["parents"] + comment = module.params["comment"] + admin = module.params["admin"] + exclusive = module.params["exclusive"] + check_mode = module.check_mode + label = module.params["label"] + + candidate_config = get_candidate(module) + running_config = get_running_config(module) + + commands = None + replace_file_path = None + connection = get_connection(module) + try: + response = connection.get_diff( + candidate=candidate_config, + running=running_config, + diff_match=match, + path=path, + diff_replace=replace, + ) + except ConnectionError as exc: + module.fail_json(msg=to_text(exc, errors="surrogate_then_replace")) + + config_diff = response.get("config_diff") + + if replace_config: + running_base_diff_resp = connection.get_diff( + candidate=running_config, + running=candidate_config, + diff_match=match, + path=path, + diff_replace=replace, + ) + if config_diff or running_base_diff_resp["config_diff"]: + ret = copy_file_to_node(module) + if not ret: + module.fail_json(msg="Copy of config file to the node failed") + + commands = ["load harddisk:/ansible_config.txt"] + replace_file_path = "harddisk:/ansible_config.txt" + + if config_diff or commands: + if not replace_config: + commands = config_diff.split("\n") + + if any((module.params["lines"], module.params["src"])): + if module.params["before"]: + commands[:0] = module.params["before"] + + if module.params["after"]: + commands.extend(module.params["after"]) + + result["commands"] = commands + + commit = not check_mode + diff = load_config( + module, + commands, + commit=commit, + replace=replace_file_path, + comment=comment, + admin=admin, + exclusive=exclusive, + label=label, + ) + if diff: + result["diff"] = dict(prepared=diff) + + result["changed"] = True + + +def main(): + """main entry point for module execution""" + backup_spec = dict(filename=dict(), dir_path=dict(type="path")) + argument_spec = dict( + src=dict(type="path"), + lines=dict(aliases=["commands"], type="list", elements="str"), + parents=dict(type="list", elements="str"), + before=dict(type="list", elements="str"), + after=dict(type="list", elements="str"), + match=dict(default="line", choices=["line", "strict", "exact", "none"]), + replace=dict(default="line", choices=["line", "block", "config"]), + # this argument is deprecated in favor of setting match: none + # it will be removed in a future version + force=dict(default=False, type="bool"), + config=dict(), + backup=dict(type="bool", default=False), + backup_options=dict(type="dict", options=backup_spec), + comment=dict(default=DEFAULT_COMMIT_COMMENT), + admin=dict(type="bool", default=False), + disable_default_comment=dict(type="bool", default=False), + exclusive=dict(type="bool", default=False), + label=dict(), + ) + + mutually_exclusive = [("lines", "src"), ("parents", "src")] + + required_if = [ + ("match", "strict", ["lines"]), + ("match", "exact", ["lines"]), + ("replace", "block", ["lines"]), + ("replace", "config", ["src"]), + ] + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + supports_check_mode=True, + ) + + if module.params["force"] is True: + module.params["match"] = "none" + if ( + module.params["disable_default_comment"] is True + and module.params["comment"] == DEFAULT_COMMIT_COMMENT + ): + module.params["comment"] = None + warnings = list() + + check_args(module, warnings) + + result = dict(changed=False, warnings=warnings) + + if module.params["backup"]: + result["__backup__"] = get_config(module) + + if any((module.params["src"], module.params["lines"])): + run(module, result) + + if result.get("changed") and any((module.params["src"], module.params["lines"])): + msg = ( + "To ensure idempotency and correct diff the input configuration lines should be" + " similar to how they appear if present in" + " the running configuration on device" + ) + if module.params["src"]: + msg += " including the indentation" + if "warnings" in result: + result["warnings"].append(msg) + else: + result["warnings"] = msg + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py new file mode 100644 index 00000000..38925b98 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The module file for iosxr_facts +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_facts +short_description: Module to collect facts from remote devices. +extends_documentation_fragment: +- cisco.iosxr.iosxr +description: +- Collects facts from network devices running the iosxr operating system. This module + places the facts gathered in the fact tree keyed by the respective resource name. The + facts module will always collect a base set of facts from the device and can enable + or disable collection of additional facts. +version_added: 1.0.0 +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +author: +- Ricardo Carrillo Cruz (@rcarrillocruz) +- Nilashish Chakraborty (@Nilashishc) +options: + gather_subset: + description: + - When supplied, this argument will restrict the facts collected to a given subset. Possible + values for this argument include all, hardware, config, and interfaces. Can + specify a list of values to include a larger subset. Values can also be used + with an initial C(!) to specify that a specific subset should not be collected. + required: false + default: 'min' + type: list + elements: str + gather_network_resources: + description: + - When supplied, this argument will restrict the facts collected to a given subset. + Possible values for this argument include all and the resources like interfaces, + lacp etc. Can specify a list of values to include a larger subset. Values can + also be used with an initial C(!) to specify that a specific subset should + not be collected. Valid subsets are 'all', 'lacp', 'lacp_interfaces', 'lldp_global', + 'lldp_interfaces', 'interfaces', 'l2_interfaces', 'l3_interfaces', 'lag_interfaces', + 'acls', 'acl_interfaces', 'static_routes', 'ospfv2'. + required: false + type: list + elements: str + available_network_resources: + description: When 'True' a list of network resources for which resource modules are available will be provided. + type: bool + default: false +""" + +EXAMPLES = """ +# Gather all facts +- cisco.iosxr.iosxr_facts: + gather_subset: all + gather_network_resources: all + +# Collect only the config and default facts +- cisco.iosxr.iosxr_facts: + gather_subset: + - config + +# Do not collect hardware facts +- cisco.iosxr.iosxr_facts: + gather_subset: + - '!hardware' + +# Collect only the lacp facts +- cisco.iosxr.iosxr_facts: + gather_subset: + - '!all' + - '!min' + gather_network_resources: + - lacp + +# Do not collect lacp_interfaces facts +- cisco.iosxr.iosxr_facts: + gather_network_resources: + - '!lacp_interfaces' + +# Collect lacp and minimal default facts +- cisco.iosxr.iosxr_facts: + gather_subset: min + gather_network_resources: lacp + +# Collect only the interfaces facts +- cisco.iosxr.iosxr_facts: + gather_subset: + - '!all' + - '!min' + gather_network_resources: + - interfaces + - l2_interfaces +""" + +RETURN = """ +ansible_net_gather_subset: + description: The list of fact subsets collected from the device + returned: always + type: list + +# default +ansible_net_version: + description: The operating system version running on the remote device + returned: always + type: str +ansible_net_hostname: + description: The configured hostname of the device + returned: always + type: str +ansible_net_image: + description: The image file the device is running + returned: always + type: str +ansible_net_api: + description: The name of the transport + returned: always + type: str +ansible_net_python_version: + description: The Python version Ansible controller is using + returned: always + type: str +ansible_net_model: + description: The model name returned from the device + returned: always + type: str + +# hardware +ansible_net_filesystems: + description: All file system names available on the device + returned: when hardware is configured + type: list +ansible_net_memfree_mb: + description: The available free memory on the remote device in Mb + returned: when hardware is configured + type: int +ansible_net_memtotal_mb: + description: The total memory on the remote device in Mb + returned: when hardware is configured + type: int + +# config +ansible_net_config: + description: The current active config from the device + returned: when config is configured + type: str + +# interfaces +ansible_net_all_ipv4_addresses: + description: All IPv4 addresses configured on the device + returned: when interfaces is configured + type: list +ansible_net_all_ipv6_addresses: + description: All IPv6 addresses configured on the device + returned: when interfaces is configured + type: list +ansible_net_interfaces: + description: A hash of all interfaces running on the system + returned: when interfaces is configured + type: dict +ansible_net_neighbors: + description: The list of LLDP neighbors from the remote device + returned: when interfaces is configured + type: dict + +# network resources +ansible_net_gather_network_resources: + description: The list of fact resource subsets collected from the device + returned: always + type: list +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.facts.facts import ( + FactsArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.facts import ( + FACT_RESOURCE_SUBSETS, + Facts, +) + + +def main(): + """ + Main entry point for module execution + + :returns: ansible_facts + """ + argument_spec = FactsArgs.argument_spec + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + warnings = [] + + ansible_facts = {} + if module.params.get("available_network_resources"): + ansible_facts["available_network_resources"] = sorted(FACT_RESOURCE_SUBSETS.keys()) + result = Facts(module).get_facts() + additional_facts, additional_warnings = result + ansible_facts.update(additional_facts) + warnings.extend(additional_warnings) + + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_hostname.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_hostname.py new file mode 100644 index 00000000..a41aaf77 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_hostname.py @@ -0,0 +1,318 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_hostname +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: iosxr_hostname +short_description: Resource module to configure hostname. +description: This module configures and manages the attributes of hostname on Cisco + IOSXR platforms. +version_added: 2.7.0 +author: Ashwini Mhatre (@amhatre) +notes: +- Tested against Cisco Iosxr 7.0.2 +- This module works with connection C(network_cli). +options: + config: + description: Hostname configuration. + type: dict + suboptions: + hostname: + description: hostname of iosxr box. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOSXR device by + executing the command B(show running-config hostname). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The states I(merged), I(replaced) and I(overridden) have identical + behaviour for this module. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command + I(show running-config hostname) executed on device. For state I(parsed) active + connection to remote host is not required. + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged + type: str +""" + +EXAMPLES = """ +# Using state: merged +# Before state: +# ------------- + +#RP/0/RP0/CPU0:ios#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +#hostname ios + +# Merged play: +# ------------ + +- name: Apply the provided configuration + cisco.iosxr.iosxr_hostname: + config: + hostname: Router1 + state: merged + +# Commands Fired: +# --------------- +# "commands": [ +# "hostname Router1", +# ], + +# After state: +# ------------ + +# RP/0/0/CPU0:Router1#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +# hostname Router1 + + +# Using state: deleted +# Before state: +# ------------- + +# RP/0/0/CPU0:Router1#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +# hostname Router1 + +# Deleted play: +# ------------- + +- name: Remove all existing configuration + cisco.iosxr.iosxr_hostname: + state: deleted + +# Commands Fired: +# --------------- + +# "commands": [ +# "no hostname Router1", +# ], + +# After state: +# ------------ +#RP/0/RP0/CPU0:ios#show running-config hostname +#Thu Jan 20 19:55:12.971 UTC +#hostname ios + +# Using state: overridden +# Before state: +# ------------- + +# RP/0/0/CPU0:ios#show running-config hostname +# hostname ios + +# Overridden play: +# ---------------- + +- name: Override commands with provided configuration + cisco.iosxr.iosxr_hostname: + config: + hostname: RouterTest + state: overridden + +# Commands Fired: +# --------------- +# "commands": [ +# "hostname RouterTest", +# ], + +# After state: +# ------------ + +#RP/0/RP0/CPU0:RouterTest#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +#hostname RouterTest + +# Using state: replaced +# Before state: +# ------------- + +#RP/0/RP0/CPU0:RouterTest#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +#hostname RouterTest + +# Replaced play: +# -------------- + +- name: Replace commands with provided configuration + cisco.iosxr.iosxr_hostname: + config: + hostname: RouterTest + state: replaced + +# Commands Fired: +# --------------- +# "commands": [], + +# After state: +# ------------ +# RP/0/0/CPU0:RouterTest#show running-config hostname +# hostname RouterTest + +# Using state: gathered +# Before state: +# ------------- + +#RP/0/RP0/CPU0:RouterTest#show running-config hostname +#Thu Jan 20 19:48:56.011 UTC +#hostname RouterTest + +# Gathered play: +# -------------- + +- name: Gather listed hostname config + cisco.iosxr.iosxr_hostname: + state: gathered + +# Module Execution Result: +# ------------------------ +# "gathered": { +# "hostname": "RouterTest" +# }, + +# Using state: rendered +# Rendered play: +# -------------- + +- name: Render the commands for provided configuration + cisco.iosxr.iosxr_hostname: + config: + hostname: RouterTest + state: rendered + +# Module Execution Result: +# ------------------------ +# "rendered": [ +# "hostname RouterTest", +# ] + +# Using state: parsed +# File: parsed.cfg +# ---------------- + +# hostname RouterTest +# Parsed play: +# ------------ + +- name: Parse the provided configuration with the existing running configuration + cisco.iosxr.iosxr_hostname: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Module Execution Result: +# ------------------------ +# "parsed": { +# "hostname": "RouterTest" +# } +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - hostname Router1 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - hostname Router1 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.hostname.hostname import ( + HostnameArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.hostname.hostname import ( + Hostname, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=HostnameArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Hostname(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_interfaces.py new file mode 100644 index 00000000..b1c169cb --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_interfaces.py @@ -0,0 +1,559 @@ +#!/usr/bin/python +# +# 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/>. +# + +""" +The module file for iosxr_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +DOCUMENTATION = """ +module: iosxr_interfaces +short_description: Resource module to configure interfaces. +description: This module manages the interface attributes on Cisco IOS-XR network + devices. +version_added: 1.0.0 +author: +- Sumit Jaiswal (@justjais) +- Rohit Thakur (@rohitthakur2590) +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +options: + config: + description: A dictionary of interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface to configure in C(type + path) format. e.g. C(GigabitEthernet0/0/0/0) + type: str + required: true + description: + description: + - Interface description. + type: str + enabled: + default: true + description: + - Administrative state of the interface. + - Set the value to C(True) to administratively enable the interface or C(False) + to disable it. + type: bool + speed: + description: + - Configure the speed for an interface. Default is auto-negotiation when not + configured. + type: int + mtu: + description: + - Sets the MTU value for the interface. Applicable for Ethernet interfaces + only. + - Refer to vendor documentation for valid values. + type: int + duplex: + description: + - Configures the interface duplex mode. Default is auto-negotiation when not + configured. + type: str + choices: + - full + - half + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - parsed + - deleted + - replaced + - rendered + - gathered + - overridden + default: merged + description: + - The state of the configuration after module completion + type: str +""" + +EXAMPLES = """ +# Using merged +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Replaced by Ansible Team +# mtu 2000 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# dot1q native vlan 1021 +# ! +- name: Configure Ethernet interfaces + cisco.iosxr.iosxr_interfaces: + config: + - name: GigabitEthernet0/0/0/2 + description: Configured by Ansible + enabled: true + - name: GigabitEthernet0/0/0/3 + description: Configured by Ansible Network + enabled: false + duplex: full + state: merged +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Configured and Merged by Ansible Network +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Configured and Merged by Ansible Network +# mtu 2600 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex full +# shutdown +# dot1q native vlan 1021 +# ! +# Using replaced +# Before state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# description Configured by Ansible +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Test +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# dot1q native vlan 1021 +# ! +- name: Configure following interfaces and replace their existing config + cisco.iosxr.iosxr_interfaces: + config: + - name: GigabitEthernet0/0/0/2 + description: Configured by Ansible + enabled: true + mtu: 2000 + - name: GigabitEthernet0/0/0/3 + description: Configured by Ansible Network + enabled: false + duplex: auto + state: replaced +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# description Configured by Ansible +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Configured and Replaced by Ansible +# mtu 2000 +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Configured and Replaced by Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 1021 +# ! +# Using overridden +# Before state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Configured by Ansible +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Configured by Ansible +# mtu 2600 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex full +# shutdown +# dot1q native vlan 1021 +# ! +- name: Override interfaces + cisco.iosxr.iosxr_interfaces: + config: + - name: GigabitEthernet0/0/0/2 + description: Configured by Ansible + enabled: true + duplex: auto + - name: GigabitEthernet0/0/0/3 + description: Configured by Ansible Network + enabled: false + speed: 1000 + state: overridden +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Configured and Overridden by Ansible Network +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# speed 1000 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Configured and Overridden by Ansible Network +# mtu 2000 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex full +# shutdown +# dot1q native vlan 1021 +# ! +# Using deleted +# Before state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# description Configured and Overridden by Ansible Network +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# speed 1000 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# description Configured and Overridden by Ansible Network +# mtu 2000 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex full +# shutdown +# dot1q native vlan 1021 +# ! +- name: Delete IOSXR interfaces as in given arguments + cisco.iosxr.iosxr_interfaces: + config: + - name: GigabitEthernet0/0/0/2 + - name: GigabitEthernet0/0/0/3 + state: deleted +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# vrf custB +# ipv4 address 178.18.169.23 255.255.255.0 +# dot1q native vlan 30 +# ! +# interface GigabitEthernet0/0/0/3 +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# dot1q native vlan 1021 +# ! +# Using parsed +# parsed.cfg +# ------------ +# +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! +# - name: Convert ACL interfaces config to argspec without connecting to the appliance +# cisco.iosxr.iosxr_interfaces: +# running_config: "{{ lookup('file', './parsed.cfg') }}" +# state: parsed +# Task Output (redacted) +# ----------------------- +# "parsed": [ +# { +# "name": "MgmtEth0/RP0/CPU0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl_1" +# }, +# { +# "direction": "out", +# "name": "acl_2" +# } +# ], +# "afi": "ipv4" +# }, +# { +# "acls": [ +# { +# "direction": "in", +# "name": "acl6_1" +# }, +# { +# "direction": "out", +# "name": "acl6_2" +# } +# ], +# "afi": "ipv6" +# } +# ], +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "access_groups": [ +# { +# "acls": [ +# { +# "direction": "out", +# "name": "acl_1" +# } +# ], +# "afi": "ipv4" +# } +# ], +# "name": "GigabitEthernet0/0/0/1" +# } +# ] +# } +# Using rendered +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + description: Configured and Merged by Ansible-Network + mtu: 110 + enabled: true + duplex: half + - name: GigabitEthernet0/0/0/1 + description: Configured and Merged by Ansible-Network + mtu: 2800 + enabled: false + speed: 100 + duplex: full + state: rendered +# Task Output (redacted) +# ----------------------- +# "rendered": [ +# "interface GigabitEthernet0/0/0/0", +# "description Configured and Merged by Ansible-Network", +# "mtu 110", +# "duplex half", +# "no shutdown", +# "interface GigabitEthernet0/0/0/1", +# "description Configured and Merged by Ansible-Network", +# "mtu 2800", +# "speed 100", +# "duplex full", +# "shutdown" +# ] +# Using gathered +# Before state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! +- name: Gather IOSXR interfaces as in given arguments + cisco.iosxr.iosxr_interfaces: + config: + state: gathered +# Task Output (redacted) +# ----------------------- +# +# "gathered": [ +# { +# "description": "test for ansible", +# "enabled": false, +# "name": "Loopback888" +# }, +# { +# "description": "Configured and Merged by Ansible-Network", +# "duplex": "half", +# "enabled": true, +# "mtu": 110, +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "enabled": false, +# "name": "GigabitEthernet0/0/0/3" +# }, +# { +# "enabled": false, +# "name": "GigabitEthernet0/0/0/4" +# } +# ] +# After state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/0/0/2', 'description: Configured by Ansible', 'shutdown'] +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.interfaces.interfaces import ( + InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.interfaces.interfaces import ( + Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=InterfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l2_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l2_interfaces.py new file mode 100644 index 00000000..2c5da2d4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l2_interfaces.py @@ -0,0 +1,706 @@ +#!/usr/bin/python +# +# 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/>. +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +GENERATOR_VERSION = "1.0" + + +DOCUMENTATION = """ +module: iosxr_l2_interfaces +short_description: Resource Module to configure L2 interfaces. +description: This module manages the Layer-2 interface attributes on Cisco IOS-XR + devices. +version_added: 1.0.0 +author: +- Sumit Jaiswal (@justjais) +- Rohit Thakur (@rohitthakur2590) +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +options: + config: + description: A dictionary of Layer-2 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface/sub-interface excluding any logical unit number, + e.g. GigabitEthernet0/0/0/1 or GigabitEthernet0/0/0/1.100. + type: str + required: true + native_vlan: + description: + - Configure a native VLAN ID for the trunk + type: int + l2transport: + description: + - Switchport mode access command to configure the interface as a layer 2 access + type: bool + l2protocol: + description: + - Configures Layer 2 protocol tunneling and protocol data unit (PDU) filtering + on an interface. + type: list + elements: dict + suboptions: + cdp: + description: + - Cisco Discovery Protocol (CDP) tunneling and data unit parameters. + choices: + - drop + - forward + - tunnel + type: str + pvst: + description: + - Configures the per-VLAN Spanning Tree Protocol (PVST) tunneling and + data unit parameters. + choices: + - drop + - forward + - tunnel + type: str + stp: + description: + - Spanning Tree Protocol (STP) tunneling and data unit parameters. + choices: + - drop + - forward + - tunnel + type: str + vtp: + description: + - VLAN Trunk Protocol (VTP) tunneling and data unit parameters. + choices: + - drop + - forward + - tunnel + type: str + cpsv: + description: + - CDP, PVST+, STP, and VTP protocols. + choices: + - drop + - reverse-tunnel + - tunnel + type: str + encapsulation: + description: Specify which packets will be matched by this sub-interface. + type: dict + suboptions: + dot1q: + type: int + description: IEEE 802.1Q VLAN-tagged packets. + second_dot1q: + type: int + description: IEEE 802.1Q VLAN-tagged packets. + q_vlan: + description: + - 802.1Q VLAN configuration. Note that it can accept either 2 VLAN IDs when + configuring Q-in-Q VLAN, or it will accept 1 VLAN ID and 'any' as input + list when configuring Q-in-any vlan as input. Note, that this option is + valid only with respect to Sub-Interface and is not valid when configuring + for Interface. + type: list + elements: int + propagate: + description: + - Propagate Layer 2 transport events. Note that it will work only when the + I(l2tranport) option is set to TRUE + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - rendered + - gathered + - parsed + default: merged + description: + - The state of the configuration after module completion + type: str +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# ! + +- name: Merge provided configuration with device configuration + cisco.iosxr.iosxr_l2_interfaces: + config: + - name: GigabitEthernet0/0/0/3 + native_vlan: 20 + - name: GigabitEthernet0/0/0/4 + native_vlan: 40 + l2transport: true + l2protocol: + - stp: tunnel + - name: GigabitEthernet0/0/0/3.900 + l2transport: true + q_vlan: + - 20 + - 40 + state: merged + +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 10 +# l2transport +# l2protocol stp tunnel +# ! +# ! +# interface GigabitEthernet0/0/0/3.900 l2transport +# dot1q vlan 20 40 +# ! + +# Using replaced +# +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 10 +# l2transport +# l2protocol stp tunnel +# ! +# ! +# interface GigabitEthernet0/0/0/3.900 l2transport +# dot1q vlan 20 40 +# ! + +- name: Replaces device configuration of listed interfaces with provided configuration + cisco.iosxr.iosxr_l2_interfaces: + config: + - name: GigabitEthernet0/0/0/4 + native_vlan: 40 + l2transport: true + l2protocol: + - stp: forward + - name: GigabitEthernet0/0/0/3.900 + q_vlan: + - 20 + - any + state: replaced + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 40 +# l2transport +# l2protocol stp forward +# ! +# ! +# interface GigabitEthernet0/0/0/3.900 l2transport +# dot1q vlan 20 any +# ! + +# Using overridden +# +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 10 +# l2transport +# l2protocol stp tunnel +# ! +# ! +# interface GigabitEthernet0/0/0/3.900 l2transport +# dot1q vlan 20 40 +# ! + +- name: Override device configuration of all interfaces with provided configuration + cisco.iosxr.iosxr_l2_interfaces: + config: + - name: GigabitEthernet0/0/0/4 + native_vlan: 40 + l2transport: true + l2protocol: + - stp: forward + - name: GigabitEthernet0/0/0/3.900 + q_vlan: + - 20 + - any + state: overridden + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 40 +# l2transport +# l2protocol stp forward +# ! +# ! +# interface GigabitEthernet0/0/0/3.900 +# dot1q vlan 20 any +# ! + +# Using deleted +# +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 10 +# l2transport +# l2protocol stp tunnel +# ! +# ! +# + +- name: "Delete L2 attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.iosxr.iosxr_l2_interfaces: + config: + - name: GigabitEthernet0/0/0/4 + state: deleted + +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# ! + +# Using Deleted without any config passed +# "(NOTE: This will delete all of configured resource module attributes from each configured interface)" +# +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# dot1q native vlan 20 +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# dot1q native vlan 10 +# l2transport +# l2protocol stp tunnel +# ! +# ! + +- name: "Delete L2 attributes of all interfaces (Note: This won't delete the interface itself)" + cisco.iosxr.iosxr_l2_interfaces: + state: deleted + +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/3 +# description Ansible Network +# vrf custB +# ipv4 address 10.10.0.2 255.255.255.0 +# duplex half +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# description Test description +# ! + + +# Using parsed +# parsed.cfg +# ------------ +# +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.900 +# encapsulation dot1q 20 second-dot1q 40 +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# dot1q native vlan 40 +# ! +- name: Convert L2 interfaces config to argspec without connecting to the appliance + cisco.iosxr.iosxr_l2_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed +# Task Output (redacted) +# ----------------------- +# "parsed": [ +# { +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "l2protocol": [ +# { +# "cdp": "forward" +# }, +# { +# "pvst": "tunnel" +# } +# ], +# "l2transport": true, +# "name": "GigabitEthernet0/0/0/1", +# "native_vlan": 10, +# "propagate": true +# }, +# { +# "name": "GigabitEthernet0/0/0/3" +# }, +# { +# "name": "GigabitEthernet0/0/0/3.900", +# "q_vlan": [ +# 20, +# 40 +# ] +# }, +# { +# "name": "GigabitEthernet0/0/0/4", +# "native_vlan": 40 +# } +# ] + + +# Using rendered +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_l2_interfaces: + config: + + - name: GigabitEthernet0/0/0/1 + native_vlan: 10 + l2transport: true + l2protocol: + + - pvst: tunnel + + - cdp: forward + propagate: true + + - name: GigabitEthernet0/0/0/3.900 + q_vlan: + - 20 + - 40 + + - name: GigabitEthernet0/0/0/4 + native_vlan: 40 + state: rendered +# Task Output (redacted) +# ----------------------- +# "rendered": [ +# "interface GigabitEthernet0/0/0/1", +# "dot1q native vlan 10", +# "l2transport l2protocol pvst tunnel", +# "l2transport l2protocol cdp forward", +# "l2transport propagate remote-status", +# "interface GigabitEthernet0/0/0/3.900", +# "dot1q vlan 20 40", +# "interface GigabitEthernet0/0/0/4", +# "dot1q native vlan 40" +# ] + + +# Using gathered +# Before state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.900 +# encapsulation dot1q 20 second-dot1q 40 +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# dot1q native vlan 40 +# ! +- name: Gather IOSXR l2 interfaces as in given arguments + cisco.iosxr.iosxr_l2_interfaces: + config: + state: gathered +# Task Output (redacted) +# ----------------------- +# +# "gathered": [ +# { +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "l2protocol": [ +# { +# "cdp": "forward" +# }, +# { +# "pvst": "tunnel" +# } +# ], +# "l2transport": true, +# "name": "GigabitEthernet0/0/0/1", +# "native_vlan": 10, +# "propagate": true +# }, +# { +# "name": "GigabitEthernet0/0/0/3" +# }, +# { +# "name": "GigabitEthernet0/0/0/3.900", +# "q_vlan": [ +# 20, +# 40 +# ] +# }, +# { +# "name": "GigabitEthernet0/0/0/4", +# "native_vlan": 40 +# } +# ] +# After state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 110 +# ipv4 address 172.31.1.1 255.255.255.0 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.900 +# encapsulation dot1q 20 second-dot1q 40 +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# dot1q native vlan 40 +# ! + + + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/0/0/2', 'l2transport l2protocol pvst tunnel'] +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.l2_interfaces.l2_interfaces import ( + L2_InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.l2_interfaces.l2_interfaces import ( + L2_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=L2_InterfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = L2_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l3_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l3_interfaces.py new file mode 100644 index 00000000..98785f6b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_l3_interfaces.py @@ -0,0 +1,672 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat Inc. +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################## +# WARNING +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +# +############################################## + +""" +The module file for ios_l3_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_l3_interfaces +short_description: Resource module to configure L3 interfaces. +description: This module provides declarative management of Layer-3 interface on Cisco + IOS-XR devices. +version_added: 1.0.0 +author: +- Sumit Jaiswal (@justjais) +- Rohit Thakur (@rohitthakur2590) +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +options: + config: + description: A dictionary of Layer-3 interface options + type: list + elements: dict + suboptions: + name: + description: + - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1. + type: str + required: true + ipv4: + description: + - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option. + - The address format is <ipv4 address>/<mask>, the mask is number in range + 0-32 eg. 192.168.0.1/24 + type: list + elements: dict + suboptions: + address: + description: + - Configures the IPv4 address for Interface. + type: str + secondary: + description: + - Configures the IP address as a secondary address. + type: bool + ipv6: + description: + - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option. + - The address format is <ipv6 address>/<mask>, the mask is number in range + 0-128 eg. fd5d:12c9:2201:1::1/64 + type: list + elements: dict + suboptions: + address: + description: + - Configures the IPv6 address for Interface. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config interface). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - rendered + - gathered + default: merged + description: + - The state of the configuration after module completion + type: str +""" + +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.0.2 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + +- name: Merge provided configuration with device configuration + cisco.iosxr.iosxr_l3_interfaces: + config: + - name: GigabitEthernet0/0/0/2 + ipv4: + - address: 192.168.0.1/24 + - name: GigabitEthernet0/0/0/3 + ipv4: + - address: 192.168.2.1/24 + secondary: true + state: merged + +# After state: +# ------------ +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# ipv4 address 192.168.0.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.1.0 255.255.255.0 +# ipv4 address 192.168.2.1 255.255.255.0 secondary +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + +# Using overridden + +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# ipv4 address 192.168.0.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.1.0 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + +- name: Override device configuration of all interfaces with provided configuration + cisco.iosxr.iosxr_l3_interfaces: + config: + - name: GigabitEthernet0/0/0/3 + ipv4: + - address: 192.168.0.1/24 + - name: GigabitEthernet0/0/0/3.700 + ipv4: + - address: 192.168.0.2/24 + - address: 192.168.2.1/24 + secondary: true + state: overridden + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.0.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ipv4 address 192.168.0.2 255.255.255.0 +# ipv4 address 192.168.2.1 255.255.255.0 secondary +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! + +# Using replaced + +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.0.2 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ipv4 address 192.168.0.1 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + +- name: Replaces device configuration of listed interfaces with provided configuration + cisco.iosxr.iosxr_l3_interfaces: + config: + - name: GigabitEthernet0/0/0/3 + ipv6: + - address: fd5d:12c9:2201:1::1/64 + - name: GigabitEthernet0/0/0/4 + ipv4: + - address: 192.168.0.2/24 + state: replaced + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ipv4 address 192.168.0.1 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv4 address 192.168.0.2 255.255.255.0 +# shutdown +# ! + +# Using deleted + +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# ipv4 address 192.168.2.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# ipv4 address 192.168.3.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.0.2 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ipv4 address 192.168.0.1 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + +- name: "Delete L3 attributes of given interfaces (Note: This won't delete the interface itself)" + cisco.iosxr.iosxr_l3_interfaces: + config: + - name: GigabitEthernet0/0/0/3 + - name: GigabitEthernet0/0/0/4 + - name: GigabitEthernet0/0/0/3.700 + state: deleted + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# ipv4 address 192.168.2.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# ipv4 address 192.168.3.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! + +# Using Deleted without any config passed +# "(NOTE: This will delete all of configured resource module attributes from each configured interface)" + +# Before state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# ipv4 address 192.168.2.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# ipv4 address 192.168.3.1 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.168.0.2 255.255.255.0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ipv4 address 192.168.0.1 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/4 +# ipv6 address fd5d:12c9:2201:1::1/64 +# shutdown +# ! + + +- name: "Delete L3 attributes of all interfaces (Note: This won't delete the interface itself)" + cisco.iosxr.iosxr_l3_interfaces: + state: deleted + +# After state: +# ------------- +# +# viosxr#show running-config interface +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3.700 +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! + + +# Using parsed +# parsed.cfg +# ------------ +# +# nterface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 66 +# ipv4 address 192.0.2.1 255.255.255.0 +# ipv4 address 192.0.2.2 255.255.255.0 secondary +# ipv6 address 2001:db8:0:3::/64 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# description Configured and Merged by Ansible-Network +# mtu 66 +# speed 100 +# duplex full +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# ipv4 address 192.0.22.1 255.255.255.0 +# ipv4 address 192.0.23.1 255.255.255.0 +# ! +# - name: Convert L3 interfaces config to argspec without connecting to the appliance +# cisco.iosxr.iosxr_l3_interfaces: +# running_config: "{{ lookup('file', './parsed.cfg') }}" +# state: parsed +# Task Output (redacted) +# ----------------------- +# "parsed": [ +# { +# "ipv4": [ +# { +# "address": "192.0.2.1 255.255.255.0" +# }, +# { +# "address": "192.0.2.2 255.255.255.0", +# "secondary": true +# } +# ], +# "ipv6": [ +# { +# "address": "2001:db8:0:3::/64" +# } +# ], +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "name": "GigabitEthernet0/0/0/1" +# }, +# { +# "ipv4": [ +# { +# "address": "192.0.22.1 255.255.255.0" +# }, +# { +# "address": "192.0.23.1 255.255.255.0" +# } +# ], +# "name": "GigabitEthernet0/0/0/3" +# } +# ] + + +# Using rendered +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_l3_interfaces: + config: + + - name: GigabitEthernet0/0/0/0 + ipv4: + + - address: 198.51.100.1/24 + + - name: GigabitEthernet0/0/0/1 + ipv6: + + - address: 2001:db8:0:3::/64 + ipv4: + + - address: 192.0.2.1/24 + + - address: 192.0.2.2/24 + secondary: true + state: rendered +# Task Output (redacted) +# ----------------------- +# "rendered": [ +# "interface GigabitEthernet0/0/0/0", +# "ipv4 address 198.51.100.1 255.255.255.0", +# "interface GigabitEthernet0/0/0/1", +# "ipv4 address 192.0.2.2 255.255.255.0 secondary", +# "ipv4 address 192.0.2.1 255.255.255.0", +# "ipv6 address 2001:db8:0:3::/64" +# ] +# Using gathered +# Before state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 66 +# ipv4 address 192.0.2.1 255.255.255.0 +# ipv4 address 192.0.2.2 255.255.255.0 secondary +# ipv6 address 2001:db8:0:3::/64 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# description Configured and Merged by Ansible-Network +# mtu 66 +# speed 100 +# duplex full +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# dot1q native vlan 40 +# ! +- name: Gather IOSXR l3 interfaces as in given arguments + cisco.iosxr.iosxr_l3_interfaces: + config: + state: gathered +# Task Output (redacted) +# ----------------------- +# +# "gathered": [ +# { +# "name": "Loopback888" +# }, +# { +# "ipv4": [ +# { +# "address": "192.0.2.1 255.255.255.0" +# }, +# { +# "address": "192.0.2.2 255.255.255.0", +# "secondary": true +# } +# ], +# "ipv6": [ +# { +# "address": "2001:db8:0:3::/64" +# } +# ], +# "name": "GigabitEthernet0/0/0/0" +# }, +# { +# "name": "GigabitEthernet0/0/0/1" +# }, +# { +# "name": "GigabitEthernet0/0/0/3" +# }, +# { +# "name": "GigabitEthernet0/0/0/4" +# } +# ] +# After state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config interface +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.70 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# description Configured and Merged by Ansible-Network +# mtu 66 +# ipv4 address 192.0.2.1 255.255.255.0 +# ipv4 address 192.0.2.2 255.255.255.0 secondary +# ipv6 address 2001:db8:0:3::/64 +# duplex half +# ! +# interface GigabitEthernet0/0/0/1 +# description Configured and Merged by Ansible-Network +# mtu 66 +# speed 100 +# duplex full +# dot1q native vlan 10 +# l2transport +# l2protocol cdp forward +# l2protocol pvst tunnel +# propagate remote-status +# ! +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# dot1q native vlan 40 +# ! + + +""" + +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: The configuration returned will always be in the same format of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: The configuration returned will always be in the same format of the parameters above. +commands: + description: The set of commands pushed to the remote device + returned: always + type: list + sample: ['interface GigabitEthernet0/0/0/1', 'ipv4 address 192.168.0.1 255.255.255.0'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.l3_interfaces.l3_interfaces import ( + L3_InterfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.l3_interfaces.l3_interfaces import ( + L3_Interfaces, +) + + +def main(): + """ + Main entry point for module execution + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=L3_InterfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = L3_Interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp.py new file mode 100644 index 00000000..7d54d992 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp.py @@ -0,0 +1,391 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_lacp +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_lacp +short_description: Resource module to configure LACP. +description: +- This module manages Global Link Aggregation Control Protocol (LACP) on IOS-XR devices. +version_added: 1.0.0 +author: +- Nilashish Chakraborty (@nilashishc) +- Rohit Thakur (@rohitthakur2590) +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +options: + config: + description: The provided configurations. + type: dict + suboptions: + system: + description: This option sets the default system parameters for LACP bundles. + type: dict + suboptions: + priority: + description: + - The system priority to use in LACP negotiations. + - Lower value is higher priority. + - Refer to vendor documentation for valid values. + type: int + mac: + type: dict + description: + - The system MAC related configuration for LACP. + suboptions: + address: + description: + - The system ID to use in LACP negotiations. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config lacp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state of the configuration after module completion. + type: str + choices: + - merged + - replaced + - deleted + - parsed + - rendered + - gathered + default: merged +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:iosxr01#show running-config lacp +# Tue Jul 16 17:46:08.147 UTC +# % No such configuration item(s) +# +# + +- name: Merge provided configuration with device configuration + cisco.iosxr.iosxr_lacp: + config: + system: + priority: 10 + mac: + address: 00c1.4c00.bd15 + state: merged + +# +# +# ----------------------- +# Module Execution Result +# ----------------------- +# +# "before": {} +# +# +# "commands": [ +# "lacp system priority 10", +# "lacp system mac 00c1.4c00.bd15" +# ] +# +# +# "after": { +# "system": { +# "mac": { +# "address": "00c1.4c00.bd15" +# }, +# "priority": 10 +# } +# } +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:iosxr01#sh run lacp +# Tue Jul 16 17:51:29.365 UTC +# lacp system mac 00c1.4c00.bd15 +# lacp system priority 10 +# +# + +# Using replaced +# +# +# ------------- +# Before state +# ------------- +# +# +# RP/0/0/CPU0:iosxr01#sh run lacp +# Tue Jul 16 17:53:59.904 UTC +# lacp system mac 00c1.4c00.bd15 +# lacp system priority 10 +# + +- name: Replace device global lacp configuration with the given configuration + cisco.iosxr.iosxr_lacp: + config: + system: + priority: 11 + state: replaced +# +# +# ----------------------- +# Module Execution Result +# ----------------------- +# "before": { +# "system": { +# "mac": { +# "address": "00c1.4c00.bd15" +# }, +# "priority": 10 +# } +# } +# +# +# "commands": [ +# "no lacp system mac", +# "lacp system priority 11" +# ] +# +# +# "after": { +# "system": { +# "priority": 11 +# } +# } +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:iosxr01#sh run lacp +# Tue Jul 16 18:02:40.379 UTC +# lacp system priority 11 +# +# + +# Using deleted +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:iosxr01#sh run lacp +# Tue Jul 16 18:37:09.727 UTC +# lacp system mac 00c1.4c00.bd15 +# lacp system priority 11 +# +# + +- name: Delete global LACP configurations from the device + cisco.iosxr.iosxr_lacp: + state: deleted + +# +# +# ----------------------- +# Module Execution Result +# ----------------------- +# "before": { +# "system": { +# "mac": { +# "address": "00c1.4c00.bd15" +# }, +# "priority": 11 +# } +# } +# +# +# "commands": [ +# "no lacp system mac", +# "no lacp system priority" +# ] +# +# +# "after": {} +# +# ------------ +# After state +# ------------ +# +# +# RP/0/0/CPU0:iosxr01#sh run lacp +# Tue Jul 16 18:39:44.116 UTC +# % No such configuration item(s) +# +# + + +# Using parsed +# parsed.cfg +# ------------ +# +# lacp system mac 00c1.4c00.bd15 +# lacp system priority 11 +# - name: Convert LACP config to argspec without connecting to the appliance +# cisco.iosxr.iosxr_lacp: +# running_config: "{{ lookup('file', './parsed.cfg') }}" +# state: parsed +# Task Output (redacted) +# ----------------------- +# "parsed": { +# "system": { +# "mac": { +# "address": "00c1.4c00.bd15" +# }, +# "priority": 11 +# } +# } + + +# Using rendered +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_lacp: + config: + system: + priority: 11 + mac: + address: 00c1.4c00.bd15 + state: rendered +# Task Output (redacted) +# ----------------------- +# "rendered": [ +# "lacp system priority 11", +# "lacp system mac 00c1.4c00.bd15" +# ] + + +# Using gathered +# Before state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config lacp +# lacp system mac 00c1.4c00.bd15 +# lacp system priority 11 +- name: Gather IOSXR LACP configuration + cisco.iosxr.iosxr_lacp: + config: + state: gathered +# Task Output (redacted) +# ----------------------- +# +# "gathered": { +# "system": { +# "mac": { +# "address": "00c1.4c00.bd15" +# }, +# "priority": 11 +# } +# } +# After state: +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config lacp +# lacp system mac 00c1.4c00.bd15 +# lacp system priority + + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: dict + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: dict + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['lacp system priority 10', 'lacp system mac 00c1.4c00.bd15'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lacp.lacp import ( + LacpArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.lacp.lacp import Lacp + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=LacpArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lacp(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp_interfaces.py new file mode 100644 index 00000000..1ebeaae8 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lacp_interfaces.py @@ -0,0 +1,653 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_lacp_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_lacp_interfaces +short_description: Resource module to configure LACP interfaces. +description: +- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces + on IOS-XR devices. +version_added: 1.0.0 +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +author: Nilashish Chakraborty (@nilashishc) +options: + config: + description: A dictionary of LACP interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier of the interface or Ether-Bundle. + type: str + churn_logging: + description: + - Specifies the parameter for logging of LACP churn events. + - Valid only for ether-bundles. + - Mode 'actor' logs actor churn events only. + - Mode 'partner' logs partner churn events only. + - Mode 'both' logs actor and partner churn events only. + type: str + choices: + - actor + - partner + - both + collector_max_delay: + description: + - Specifies the collector max delay to be signaled to the LACP partner. + - Valid only for ether-bundles. + - Refer to vendor documentation for valid values. + type: int + period: + description: + - Specifies the rate at which packets are sent or received. + - For ether-bundles, this specifies the period to be used by its member links. + - Refer to vendor documentation for valid values. + type: int + switchover_suppress_flaps: + description: + - Specifies the time for which to suppress flaps during a LACP switchover. + - Valid only for ether-bundles. + - Refer to vendor documentation for valid values. + type: int + system: + description: + - This dict object contains configurable options related to LACP system parameters + for ether-bundles. + type: dict + suboptions: + priority: + description: + - Specifies the system priority to use in LACP negotiations for the bundle. + - Refer to vendor documentation for valid values. + type: int + mac: + description: + - Specifies the system ID to use in LACP negotiations for the bundle, + encoded as a MAC address. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config int). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - gathered + - rendered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# +# +# RP/0/0/CPU0:an-iosxr#sh running-config interface +# Sun Jul 21 18:01:35.079 UTC +# interface Bundle-Ether10 +# ! +# interface Bundle-Ether11 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1' +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# + +- name: Merge provided configuration with device configuration + cisco.iosxr.iosxr_lacp_interfaces: + config: + - name: Bundle-Ether10 + churn_logging: actor + collector_max_delay: 100 + switchover_suppress_flaps: 500 + + - name: Bundle-Ether11 + system: + mac: 00c2.4c00.bd15 + + - name: GigabitEthernet0/0/0/1 + period: 200 + state: merged + +# +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Jul 21 18:24:52.413 UTC +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# + + +# Using replaced +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Jul 21 18:24:52.413 UTC +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# + +- name: Replace LACP configuration of listed interfaces with provided configuration + cisco.iosxr.iosxr_lacp_interfaces: + config: + - name: Bundle-Ether10 + churn_logging: partner + + - name: GigabitEthernet0/0/0/2 + period: 300 + state: replaced + +# +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Jul 21 18:50:21.929 UTC +# interface Bundle-Ether10 +# lacp churn logging partner +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# lacp period 300 +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# + + +# Using overridden +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Jul 21 18:24:52.413 UTC +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# + +- name: Override all interface LACP configuration with provided configuration + cisco.iosxr.iosxr_lacp_interfaces: + config: + - name: Bundle-Ether12 + churn_logging: both + collector_max_delay: 100 + switchover_suppress_flaps: 500 + + - name: GigabitEthernet0/0/0/1 + period: 300 + state: overridden + +# +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:an-iosxr(config-if)#do sh run int +# Sun Jul 21 19:32:36.115 UTC +# interface Bundle-Ether10 +# ! +# interface Bundle-Ether11 +# ! +# interface Bundle-Ether12 +# lacp churn logging both +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 300 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# + + +# Using deleted +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Jul 21 18:24:52.413 UTC +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp non-revertive +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# lacp period 200 +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# lacp period 300 +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# + +- name: Deleted LACP configurations of provided interfaces (Note - This won't delete + the interface itself) + cisco.iosxr.iosxr_lacp_interfaces: + config: + - name: Bundle-Ether10 + - name: Bundle-Ether11 + - name: GigabitEthernet0/0/0/1 + - name: GigabitEthernet0/0/0/2 + state: deleted + +# +# +# ----------- +# After state +# ----------- +# +# +# Using parsed: + +# parsed.cfg +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# lacp period 200 +# ! +# + +- name: Convert lacp interfaces config to argspec without connecting to the appliance + cisco.iosxr.iosxr_lacp_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# -------------- +# Output: +# -------------- + +# parsed: +# - name: Bundle-Ether10 +# churn_logging: actor +# collector_max_delay: 100 +# switchover_suppress_flaps: 500 +# +# - name: Bundle-Ether11 +# system: +# mac: 00c2.4c00.bd15 +# +# - name: GigabitEthernet0/0/0/1 +# period: 200 +# +# + +# Using gathered: + +# Native config: +# interface Bundle-Ether10 +# lacp churn logging actor +# lacp switchover suppress-flaps 500 +# lacp collector-max-delay 100 +# ! +# interface Bundle-Ether11 +# lacp system mac 00c2.4c00.bd15 +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# lacp period 200 +# ! +# + +- name: Gather IOSXR lacp interfaces configuration + cisco.iosxr.iosxr_lacp_interfaces: + config: + state: gathered + +# ---------- +# Output +# --------- +# gathered: +# - name: Bundle-Ether10 +# churn_logging: actor +# collector_max_delay: 100 +# switchover_suppress_flaps: 500 +# +# - name: Bundle-Ether11 +# system: +# mac: 00c2.4c00.bd15 +# +# - name: GigabitEthernet0/0/0/1 +# period: 200 + +# Using rendered: + +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_lacp_interfaces: + config: + - name: Bundle-Ether10 + churn_logging: actor + collector_max_delay: 100 + switchover_suppress_flaps: 500 + + - name: Bundle-Ether11 + system: + mac: 00c2.4c00.bd15 + + - name: GigabitEthernet0/0/0/1 + period: 200 + state: rendered + +# ------------- +# Output +# ------------- +# rendered: [ +# - "interface Bundle-Ether10" +# - " lacp churn logging actor" +# - " lacp switchover suppress-flaps 500" +# - " lacp collector-max-delay 100" +# - "interface Bundle-Ether11" +# - " lacp system mac 00c2.4c00.bd15" +# - "interface MgmtEth0/0/CPU0/0" +# - " ipv4 address 192.0.2.11 255.255.255.0" +# - "interface GigabitEthernet0/0/0/1" +# - " lacp period 200" +# + + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface Bundle-Ether10', 'lacp churn logging partner', 'lacp period 150'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lacp_interfaces.lacp_interfaces import ( + Lacp_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.lacp_interfaces.lacp_interfaces import ( + Lacp_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Lacp_interfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lacp_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lag_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lag_interfaces.py new file mode 100644 index 00000000..6d1dacec --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lag_interfaces.py @@ -0,0 +1,854 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_lag_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +DOCUMENTATION = """ +module: iosxr_lag_interfaces +short_description: Resource module to configure LAG interfaces. +description: +- This module manages the attributes of LAG/Ether-Bundle interfaces on IOS-XR devices. +version_added: 1.0.0 +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +author: Nilashish Chakraborty (@NilashishC) +options: + config: + description: A provided Link Aggregation Group (LAG) configuration. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier of the LAG/Ether-Bundle to configure. + type: str + required: true + members: + description: + - List of member interfaces for the LAG/Ether-Bundle. + type: list + elements: dict + suboptions: + member: + description: + - Name of the member interface. + type: str + mode: + description: + - Specifies the mode of the operation for the member interface. + - Mode 'active' runs LACP in active mode. + - Mode 'on' does not run LACP over the port. + - Mode 'passive' runs LACP in passive mode over the port. + - Mode 'inherit' runs LACP as configured in the bundle. + type: str + choices: ["on", "active", "passive", "inherit"] + mode: + description: + - LAG mode. + - Mode 'active' runs LACP in active mode over the port. + - Mode 'on' does not run LACP over the port. + - Mode 'passive' runs LACP in passive mode over the port. + type: str + choices: ["on", "active", "passive"] + links: + description: + - This dict contains configurable options related to LAG/Ether-Bundle links. + type: dict + suboptions: + max_active: + description: + - Specifies the limit on the number of links that can be active in the LAG/Ether-Bundle. + - Refer to vendor documentation for valid values. + type: int + min_active: + description: + - Specifies the minimum number of active links needed to bring up the LAG/Ether-Bundle. + - Refer to vendor documentation for valid values. + type: int + load_balancing_hash: + description: + - Specifies the hash function used for traffic forwarded over the LAG/Ether-Bundle. + - Option 'dst-ip' uses the destination IP as the hash function. + - Option 'src-ip' uses the source IP as the hash function. + type: str + choices: ["dst-ip", "src-ip"] + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config int). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - rendered + - gathered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# RP/0/0/CPU0:iosxr01#show run int +# Sun Jul 7 19:42:59.416 UTC +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description "GigabitEthernet - 1" +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# +- name: Merge provided configuration with device configuration + cisco.iosxr.iosxr_lag_interfaces: + config: + - name: Bundle-Ether10 + members: + - member: GigabitEthernet0/0/0/1 + mode: inherit + - member: GigabitEthernet0/0/0/3 + mode: inherit + mode: active + links: + max_active: 5 + min_active: 2 + load_balancing_hash: src-ip + + - name: Bundle-Ether12 + members: + - member: GigabitEthernet0/0/0/2 + mode: passive + - member: GigabitEthernet0/0/0/4 + mode: passive + load_balancing_hash: dst-ip + state: merged +# +# +# ----------- +# After state +# ----------- +# +# RP/0/0/CPU0:iosxr01#show run int +# Sun Jul 7 20:51:17.685 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether12 +# bundle load-balancing hash dst-ip +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode passive +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 12 mode passive +# ! +# + + +# Using replaced +# +# +# ------------- +# Before state +# ------------- +# +# +# RP/0/0/CPU0:iosxr01#sho run int +# Sun Jul 7 20:58:06.527 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether12 +# bundle load-balancing hash dst-ip +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode passive +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 12 mode passive +# ! +# +# +- name: Replace device configuration of listed Bundles with provided configurations + cisco.iosxr.iosxr_lag_interfaces: + config: + - name: Bundle-Ether12 + members: + - name: GigabitEthernet0/0/0/2 + mode: passive + + - name: Bundle-Ether11 + members: + - name: GigabitEthernet0/0/0/4 + load_balancing_hash: src-ip + state: replaced +# +# +# ----------- +# After state +# ----------- +# +# +# RP/0/0/CPU0:iosxr01#sh run int +# Sun Jul 7 21:22:27.397 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether11 +# bundle load-balancing hash src-ip +# ! +# interface Bundle-Ether12 +# lacp mode passive +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode on +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 11 mode on +# ! +# +# + + +# Using overridden +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:iosxr01#sh run int +# Sun Jul 7 21:22:27.397 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether11 +# bundle load-balancing hash src-ip +# ! +# interface Bundle-Ether12 +# lacp mode passive +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode on +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 11 mode on +# ! +# +# + +- name: Overrides all device configuration with provided configuration + cisco.iosxr.iosxr_lag_interfaces: + config: + - name: Bundle-Ether10 + members: + - member: GigabitEthernet0/0/0/1 + mode: inherit + - member: GigabitEthernet0/0/0/2 + mode: inherit + mode: active + load_balancing_hash: dst-ip + state: overridden +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/0/CPU0:iosxr01#sh run int +# Sun Jul 7 21:43:04.802 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash dst-ip +# ! +# interface Bundle-Ether11 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# + + +# Using deleted +# +# +# ------------ +# Before state +# ------------ +# +# RP/0/0/CPU0:iosxr01#sh run int +# Sun Jul 7 21:22:27.397 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether11 +# bundle load-balancing hash src-ip +# ! +# interface Bundle-Ether12 +# lacp mode passive +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode on +# !n +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 11 mode on +# ! +# +# + +- name: Delete attributes of given bundles and removes member interfaces from them + (Note - This won't delete the bundles themselves) + cisco.iosxr.iosxr_lag_interfaces: + config: + - name: Bundle-Ether10 + - name: Bundle-Ether11 + - name: Bundle-Ether12 + state: deleted + +# +# +# ------------ +# After state +# ------------ +# +# RP/0/0/CPU0:iosxr01#sh run int +# Sun Jul 7 21:49:50.004 UTC +# interface Bundle-Ether10 +# ! +# interface Bundle-Ether11 +# ! +# interface Bundle-Ether12 +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# ! +# +# + +# Using deleted (without config) +# +# +# ------------ +# Before state +# ------------ +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Aug 18 19:49:51.908 UTC +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 10 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether11 +# bundle load-balancing hash dst-ip +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/1 +# bundle id 10 mode inherit +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# bundle id 10 mode passive +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# bundle id 11 mode passive +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# bundle id 11 mode passive +# shutdown +# ! +# + +- name: Delete attributes of all bundles and removes member interfaces from them (Note + - This won't delete the bundles themselves) + cisco.iosxr.iosxr_lag_interfaces: + state: deleted + +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run int +# Sun Aug 18 19:54:22.389 UTC +# interface Bundle-Ether10 +# ! +# interface Bundle-Ether11 +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 10.8.38.69 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/0 +# shutdown +# ! +# interface GigabitEthernet0/0/0/1 +# shutdown +# ! +# interface GigabitEthernet0/0/0/2 +# shutdown +# ! +# interface GigabitEthernet0/0/0/3 +# shutdown +# ! +# interface GigabitEthernet0/0/0/4 +# shutdown +# ! + +# Using parsed: + +# parsed.cfg + +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether12 +# bundle load-balancing hash dst-ip +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode passive +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 12 mode passive +# ! +# +- name: Convert lag interfaces config to argspec without connecting to the appliance + cisco.iosxr.iosxr_lag_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# -------------- +# Output +# -------------- +# parsed: +# - name: Bundle-Ether10 +# members: +# - member: GigabitEthernet0/0/0/1 +# mode: inherit +# - member: GigabitEthernet0/0/0/3 +# mode: inherit +# mode: active +# links: +# max_active: 5 +# min_active: 2 +# load_balancing_hash: src-ip + +# - name: Bundle-Ether12 +# members: +# - member: GigabitEthernet0/0/0/2 +# mode: passive +# - member: GigabitEthernet0/0/0/4 +# mode: passive +# load_balancing_hash: dst-ip + +# using gathered + +# Device Config: +# ------------- + +# interface Bundle-Ether10 +# lacp mode active +# bundle load-balancing hash src-ip +# bundle maximum-active links 5 +# bundle minimum-active links 2 +# ! +# interface Bundle-Ether12 +# bundle load-balancing hash dst-ip +# ! +# interface Loopback888 +# description test for ansible +# shutdown +# ! +# interface MgmtEth0/0/CPU0/0 +# ipv4 address 192.0.2.11 255.255.255.0 +# ! +# interface GigabitEthernet0/0/0/1 +# description 'GigabitEthernet - 1" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/2 +# description "GigabitEthernet - 2" +# bundle id 12 mode passive +# ! +# interface GigabitEthernet0/0/0/3 +# description "GigabitEthernet - 3" +# bundle id 10 mode inherit +# ! +# interface GigabitEthernet0/0/0/4 +# description "GigabitEthernet - 4" +# bundle id 12 mode passive +# ! +# + +- name: Gather IOSXR lag interfaces configuration + cisco.iosxr.iosxr_lag_interfaces: + config: + state: gathered + +# -------------- +# Output +# -------------- +# gathered: +# - name: Bundle-Ether10 +# members: +# - member: GigabitEthernet0/0/0/1 +# mode: inherit +# - member: GigabitEthernet0/0/0/3 +# mode: inherit +# mode: active +# links: +# max_active: 5 +# min_active: 2 +# load_balancing_hash: src-ip + +# - name: Bundle-Ether12 +# members: +# - member: GigabitEthernet0/0/0/2 +# mode: passive +# - member: GigabitEthernet0/0/0/4 +# mode: passive +# load_balancing_hash: dst-ip + +# Using rendered: +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_lag_interfaces: + config: + - name: Bundle-Ether10 + members: + - member: GigabitEthernet0/0/0/1 + mode: inherit + - member: GigabitEthernet0/0/0/3 + mode: inherit + mode: active + links: + max_active: 5 + min_active: 2 + load_balancing_hash: src-ip + + - name: Bundle-Ether12 + members: + - member: GigabitEthernet0/0/0/2 + mode: passive + - member: GigabitEthernet0/0/0/4 + mode: passive + load_balancing_hash: dst-ip + state: rendered + +# Output: + +# rendered: +# [ +# - "interface Bundle-Ether10" +# - " lacp mode active" +# - " bundle load-balancing hash src-ip" +# - " bundle maximum-active links 5" +# - " bundle minimum-active links 2" +# - "interface Bundle-Ether12" +# - " bundle load-balancing hash dst-ip" +# - "interface Loopback888" +# - " description test for ansible" +# - " shutdown" +# - "interface MgmtEth0/0/CPU0/0" +# - " ipv4 address 192.0.2.11 255.255.255.0" +# - "interface GigabitEthernet0/0/0/1" +# - " description 'GigabitEthernet - 1"" +# - " bundle id 10 mode inherit" +# - "interface GigabitEthernet0/0/0/2" +# - " description "GigabitEthernet - 2"" +# - " bundle id 12 mode passive" +# - "interface GigabitEthernet0/0/0/3" +# - " description "GigabitEthernet - 3"" +# - " bundle id 10 mode inherit" +# - "interface GigabitEthernet0/0/0/4" +# - " description "GigabitEthernet - 4"" +# - " bundle id 12 mode passive" +# ] +# +# + + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface Bundle-Ether10', 'bundle minimum-active links 2', 'bundle load-balancing hash src-ip'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lag_interfaces.lag_interfaces import ( + Lag_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.lag_interfaces.lag_interfaces import ( + Lag_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Lag_interfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lag_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_global.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_global.py new file mode 100644 index 00000000..9c99fc8a --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_global.py @@ -0,0 +1,490 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_lldp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_lldp_global +short_description: Resource module to configure LLDP. +description: +- This module manages Global Link Layer Discovery Protocol (LLDP) settings on IOS-XR + devices. +version_added: 1.0.0 +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +author: Nilashish Chakraborty (@NilashishC) +options: + config: + description: The provided global LLDP configuration. + type: dict + suboptions: + holdtime: + description: + - Specifies the holdtime (in sec) to be sent in packets. + type: int + reinit: + description: + - Specifies the delay (in sec) for LLDP initialization on any interface. + type: int + subinterfaces: + description: + - Enable or disable LLDP over sub-interfaces. + type: bool + timer: + description: + - Specifies the rate at which LLDP packets are sent (in sec). + type: int + tlv_select: + description: + - Specifies the LLDP TLVs to enable or disable. + type: dict + suboptions: + management_address: + description: + - Enable or disable management address TLV. + type: bool + port_description: + description: + - Enable or disable port description TLV. + type: bool + system_capabilities: + description: + - Enable or disable system capabilities TLV. + type: bool + system_description: + description: + - Enable or disable system description TLV. + type: bool + system_name: + description: + - Enable or disable system name TLV. + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config lldp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state of the configuration after module completion. + type: str + choices: + - merged + - replaced + - deleted + - parsed + - gathered + - rendered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------- +# Before State +# ------------- +# +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 19:27:54.933 UTC +# % No such configuration item(s) +# +# + +- name: Merge provided LLDP configuration with the existing configuration + cisco.iosxr.iosxr_lldp_global: + config: + holdtime: 100 + reinit: 2 + timer: 3000 + subinterfaces: true + tlv_select: + management_address: false + system_description: false + state: merged + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": {} +# +# "commands": [ +# "lldp subinterfaces enable", +# "lldp holdtime 100", +# "lldp reinit 2", +# "lldp tlv-select system-description disable", +# "lldp tlv-select management-address disable", +# "lldp timer 3000" +# ] +# +# "after": { +# "holdtime": 100, +# "reinit": 2, +# "subinterfaces": true, +# "timer": 3000, +# "tlv_select": { +# "management_address": false, +# "system_description": false +# } +# } +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 21:31:10.587 UTC +# lldp +# timer 3000 +# reinit 2 +# subinterfaces enable +# holdtime 100 +# tlv-select +# management-address disable +# system-description disable +# ! +# ! +# +# + + +# Using replaced +# +# +# ------------- +# Before State +# ------------- +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 21:31:10.587 UTC +# lldp +# timer 3000 +# reinit 2 +# subinterfaces enable +# holdtime 100 +# tlv-select +# management-address disable +# system-description disable +# ! +# ! +# +# + +- name: Replace existing LLDP device configuration with provided configuration + cisco.iosxr.iosxr_lldp_global: + config: + holdtime: 100 + tlv_select: + port_description: false + system_description: true + management_description: true + state: replaced + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "holdtime": 100, +# "reinit": 2, +# "subinterfaces": true, +# "timer": 3000, +# "tlv_select": { +# "management_address": false, +# "system_description": false +# } +# } +# +# "commands": [ +# "no lldp reinit 2", +# "no lldp subinterfaces enable", +# "no lldp timer 3000", +# "no lldp tlv-select management-address disable", +# "no lldp tlv-select system-description disable", +# "lldp tlv-select port-description disable" +# ] +# +# "after": { +# "holdtime": 100, +# "tlv_select": { +# "port_description": false +# } +# } +# +# +# ------------ +# After state +# ------------ +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 21:53:08.407 UTC +# lldp +# holdtime 100 +# tlv-select +# port-description disable +# ! +# ! +# +# + + +# Using deleted +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 21:31:10.587 UTC +# lldp +# timer 3000 +# reinit 2 +# subinterfaces enable +# holdtime 100 +# tlv-select +# management-address disable +# system-description disable +# ! +# ! +# +# + +- name: Deleted existing LLDP configurations from the device + cisco.iosxr.iosxr_lldp_global: + state: deleted + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "holdtime": 100, +# "reinit": 2, +# "subinterfaces": true, +# "timer": 3000, +# "tlv_select": { +# "management_address": false, +# "system_description": false +# } +# }, +# +# "commands": [ +# "no lldp holdtime 100", +# "no lldp reinit 2", +# "no lldp subinterfaces enable", +# "no lldp timer 3000", +# "no lldp tlv-select management-address disable", +# "no lldp tlv-select system-description disable" +# ] +# +# "after": {} +# +# +# ----------- +# After state +# ----------- +# +# RP/0/0/CPU0:an-iosxr#sh run lldp +# Tue Aug 6 21:38:31.187 UTC +# lldp +# ! +# +# Using parsed: + +# parsed.cfg +# lldp +# timer 3000 +# reinit 2 +# subinterfaces enable +# holdtime 100 +# tlv-select +# management-address disable +# system-description disable +# ! +# ! + +- name: Convert lldp global config to argspec without connecting to the appliance + cisco.iosxr.iosxr_lldp_global: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# ------------------------ +# Module Execution Result +# ------------------------ +# parsed: +# holdtime: 100 +# reinit: 2 +# timer: 3000 +# subinterfaces: True +# tlv_select: +# management_address: False +# system_description: False + +# using gathered: + +# Device config: +# lldp +# timer 3000 +# reinit 2 +# subinterfaces enable +# holdtime 100 +# tlv-select +# management-address disable +# system-description disable +# ! +# ! + +- name: Gather IOSXR lldp global configuration + cisco.iosxr.iosxr_lldp_global: + config: + state: gathered + + +# ------------------------ +# Module Execution Result +# ------------------------ +# gathered: +# holdtime: 100 +# reinit: 2 +# timer: 3000 +# subinterfaces: True +# tlv_select: +# management_address: False +# system_description: False + +# using rendered: + +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_lldp_global: + config: + holdtime: 100 + reinit: 2 + timer: 3000 + subinterfaces: true + tlv_select: + management_address: false + system_description: false + state: rendered + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "rendered": [ +# "lldp subinterfaces enable", +# "lldp holdtime 100", +# "lldp reinit 2", +# "lldp tlv-select system-description disable", +# "lldp tlv-select management-address disable", +# "lldp timer 3000" +# ] + + + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: dict + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: dict + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['lldp subinterfaces enable', 'lldp holdtime 100', 'no lldp tlv-select management-address disable'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lldp_global.lldp_global import ( + Lldp_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.lldp_global.lldp_global import ( + Lldp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Lldp_globalArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lldp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_interfaces.py new file mode 100644 index 00000000..f88d132e --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_lldp_interfaces.py @@ -0,0 +1,725 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_lldp_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_lldp_interfaces +short_description: Resource module to configure LLDP interfaces. +description: +- This module manages Link Layer Discovery Protocol (LLDP) attributes of interfaces + on IOS-XR devices. +version_added: 1.0.0 +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +author: Nilashish Chakraborty (@nilashishc) +options: + config: + description: A dictionary of LLDP interfaces options. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier of the interface or Ether-Bundle. + type: str + destination: + description: + - Specifies LLDP destination configuration on the interface. + suboptions: + mac_address: + description: + - Specifies the LLDP destination mac address on the interface. + type: str + choices: + - ieee-nearest-bridge + - ieee-nearest-non-tmpr-bridge + type: dict + receive: + description: + - Enable/disable LLDP RX on an interface. + type: bool + transmit: + description: + - Enable/disable LLDP TX on an interface. + type: bool + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config int). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state of the configuration after module completion. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - rendered + - gathered + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 12:40:23.104 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# ! +# +# + +- name: Merge provided configuration with running configuration + cisco.iosxr.iosxr_lldp_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + destination: + mac_address: ieee-nearest-non-tmpr-bridge + transmit: false + + - name: GigabitEthernet0/0/0/2 + destination: + mac_address: ieee-nearest-bridge + receive: false + state: merged + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# +# "before": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "name": "GigabitEthernet0/0/0/1" +# }, +# { +# "name": "GigabitEthernet0/0/0/2" +# } +# ] +# +# "commands": [ +# "interface GigabitEthernet0/0/0/2", +# "lldp destination mac-address ieee-nearest-non-tmpr-bridge", +# "lldp transmit disable", +# "interface GigabitEthernet0/0/0/1", +# "lldp receive disable", +# "lldp destination mac-address ieee-nearest-bridge" +# ] +# +# "after": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-bridge" +# }, +# "name": "GigabitEthernet0/0/0/1", +# "receive": false +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/2", +# "transmit": false +# } +# ] +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 12:49:51.517 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# +# + + +# Using replaced +# +# +# ------------- +# Before state +# ------------- +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 12:49:51.517 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# +# + +- name: Replace existing LLDP configurations of specified interfaces with provided + configuration + cisco.iosxr.iosxr_lldp_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + destination: + mac_address: ieee-nearest-non-tmpr-bridge + state: replaced + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-bridge" +# }, +# "name": "GigabitEthernet0/0/0/1", +# "receive": false +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/2", +# "transmit": false +# } +# ] +# +# +# "commands": [ +# "interface GigabitEthernet0/0/0/1", +# "no lldp receive disable", +# "lldp destination mac-address ieee-nearest-non-tmpr-bridge" +# ] +# +# +# "after": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/1" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/2", +# "transmit": false +# } +# ] +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 13:02:57.062 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# +# + + +# Using overridden +# +# +# ------------- +# Before state +# ------------- +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 13:15:40.465 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# +# + +- name: Override the LLDP configurations of all the interfaces with provided configurations + cisco.iosxr.iosxr_lldp_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + transmit: false + state: overridden + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# +# "before": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-bridge" +# }, +# "name": "GigabitEthernet0/0/0/1", +# "receive": false +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/2", +# "transmit": false +# } +# ] +# +# "commands": [ +# "interface GigabitEthernet0/0/0/2", +# "no lldp destination mac-address ieee-nearest-non-tmpr-bridge", +# "no lldp transmit disable", +# "interface GigabitEthernet0/0/0/1", +# "no lldp destination mac-address ieee-nearest-bridge", +# "no lldp receive disable", +# "lldp transmit disable" +# ] +# +# +# "after": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "name": "GigabitEthernet0/0/0/1", +# "transmit": false +# }, +# { +# "name": "GigabitEthernet0/0/0/2" +# } +# ] +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 13:22:25.604 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# transmit disable +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# ! +# +# + + +# Using deleted +# +# +# ------------- +# Before state +# ------------- +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 13:26:21.498 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge +# ! +# ! +# ! +# +# + +- name: Delete LLDP configurations of all interfaces (Note - This won't delete the + interfaces themselves) + cisco.iosxr.iosxr_lldp_interfaces: + state: deleted + +# +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# +# "before": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-bridge" +# }, +# "name": "GigabitEthernet0/0/0/1", +# "receive": false +# }, +# { +# "destination": { +# "mac_address": "ieee-nearest-non-tmpr-bridge" +# }, +# "name": "GigabitEthernet0/0/0/2", +# "transmit": false +# } +# ] +# +# +# "commands": [ +# "interface GigabitEthernet0/0/0/1", +# "no lldp destination mac-address ieee-nearest-bridge", +# "no lldp receive disable", +# "interface GigabitEthernet0/0/0/2", +# "no lldp destination mac-address ieee-nearest-non-tmpr-bridge", +# "no lldp transmit disable" +# ] +# +# +# "after": [ +# { +# "name": "TenGigE0/0/0/0" +# }, +# { +# "name": "GigabitEthernet0/0/0/1" +# }, +# { +# "name": "GigabitEthernet0/0/0/2" +# } +# ] +# +# +# ------------ +# After state +# ------------ +# +# +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 13:30:14.618 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# ! +# +# +# Using parsed: +# parsed.cfg + +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge + +- name: Convert lacp interfaces config to argspec without connecting to the appliance + cisco.iosxr.iosxr_lldp_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed + +# ------------------------ +# Module Execution Result +# ------------------------ + +# parsed: [ +# - name: GigabitEthernet0/0/0/1 +# destination: +# mac_address: ieee-nearest-non-tmpr-bridge +# transmit: False + +# - name: GigabitEthernet0/0/0/2 +# destination: +# mac_address: ieee-nearest-bridge +# receive: False +# ] + +# Using gathered: +# Device config: + +# RP/0/RP0/CPU0:ios#sh run int +# Mon Aug 12 12:49:51.517 UTC +# interface TenGigE0/0/0/0 +# ipv4 address 192.0.2.11 255.255.255.192 +# ! +# interface preconfigure GigabitEthernet0/0/0/1 +# lldp +# receive disable +# destination mac-address +# ieee-nearest-bridge +# ! +# ! +# ! +# interface preconfigure GigabitEthernet0/0/0/2 +# lldp +# transmit disable +# destination mac-address +# ieee-nearest-non-tmpr-bridge + +- name: Gather IOSXR lldp interfaces configuration + cisco.iosxr.iosxr_lldp_interfaces: + config: + state: gathered + +# ------------------------ +# Module Execution Result +# ------------------------ + +# gathered: +# - name: GigabitEthernet0/0/0/1 +# destination: +# mac_address: ieee-nearest-non-tmpr-bridge +# transmit: False + +# - name: GigabitEthernet0/0/0/2 +# destination: +# mac_address: ieee-nearest-bridge +# receive: False + +# Using rendred: +- name: Render platform specific commands from task input using rendered state + cisco.iosxr.iosxr_lldp_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + destination: + mac_address: ieee-nearest-non-tmpr-bridge + transmit: false + + - name: GigabitEthernet0/0/0/2 + destination: + mac_address: ieee-nearest-bridge + receive: false + state: rendered + +# ------------------------ +# Module Execution Result +# ------------------------ + +# "rendered": [ +# "interface GigabitEthernet0/0/0/2", +# "lldp destination mac-address ieee-nearest-non-tmpr-bridge", +# "lldp transmit disable", +# "interface GigabitEthernet0/0/0/1", +# "lldp receive disable", +# "lldp destination mac-address ieee-nearest-bridge" +# ] + +""" +RETURN = """ +before: + description: The configuration as structured data prior to module invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The configuration as structured data after module completion. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: ['interface GigabitEthernet0/0/0/1', 'lldp destination mac-address ieee-nearest-non-tmpr-bridge', 'no lldp transmit disable'] +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.lldp_interfaces.lldp_interfaces import ( + Lldp_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.lldp_interfaces.lldp_interfaces import ( + Lldp_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Lldp_interfacesArgs.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + + result = Lldp_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py new file mode 100644 index 00000000..9889f568 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py @@ -0,0 +1,1270 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_logging +author: +- Trishna Guha (@trishnaguha) +- Kedar Kekan (@kedarX) +short_description: (deprecated, removed after 2023-08-01) Configuration management of system logging services on network + devices +description: +- This module provides declarative management configuration of system logging (syslog) + on Cisco IOS XR devices. +version_added: 1.0.0 +deprecated: + alternative: iosxr_logging_global + why: Updated module released with more functionality. + removed_at_date: '2023-08-01' +requirements: +- ncclient >= 0.5.3 when using netconf +- lxml >= 4.1.1 when using netconf +notes: +- This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR + Platform Options,../network/user_guide/platform_iosxr.html). +options: + dest: + description: + - Destination for system logging (syslog) messages. + choices: + - host + - console + - monitor + - buffered + - file + type: str + name: + description: + - When C(dest) = I(file) name indicates file-name + - When C(dest) = I(host) name indicates the host-name or ip-address of syslog + server. + type: str + vrf: + description: + - vrf name when syslog server is configured, C(dest) = C(host) + type: str + default: default + size: + description: + - Size of buffer when C(dest) = C(buffered). The acceptable value is in the range + I(307200 to 125000000 bytes). Default 307200 + - Size of file when C(dest) = C(file). The acceptable value is in the range I(1 + to 2097152)KB. Default 2 GB + type: int + facility: + description: + - To configure the type of syslog facility in which system logging (syslog) messages + are sent to syslog servers Optional config for C(dest) = C(host) + default: local7 + type: str + hostnameprefix: + description: + - To append a hostname prefix to system logging (syslog) messages logged to syslog + servers. Optional config for C(dest) = C(host) + type: str + level: + description: + - Specifies the severity level for the logging. + type: str + default: debugging + aliases: + - severity + choices: ["emergencies", "alerts", "critical", "errors", "warning", "notifications", "informational", "debugging"] + path: + description: + Set file path. + type: str + aggregate: + description: List of syslog logging configuration definitions. + type: list + elements: dict + suboptions: + dest: + description: + - Destination for system logging (syslog) messages. + choices: + - host + - console + - monitor + - buffered + - file + type: str + name: + description: + - When C(dest) = I(file) name indicates file-name + - When C(dest) = I(host) name indicates the host-name or ip-address of syslog + server. + type: str + path: + description: + Set file path. + type: str + vrf: + description: + - vrf name when syslog server is configured, C(dest) = C(host) + type: str + size: + description: + - Size of buffer when C(dest) = C(buffered). The acceptable value is in the range + I(307200 to 125000000 bytes). Default 307200 + - Size of file when C(dest) = C(file). The acceptable value is in the range I(1 + to 2097152)KB. Default 2 GB + type: int + facility: + description: + - To configure the type of syslog facility in which system logging (syslog) messages + are sent to syslog servers Optional config for C(dest) = C(host) + type: str + hostnameprefix: + description: + - To append a hostname prefix to system logging (syslog) messages logged to syslog + servers. Optional config for C(dest) = C(host) + type: str + level: + description: + - Specifies the severity level for the logging. + type: str + aliases: + - severity + choices: ["emergencies", "alerts", "critical", "errors", "warning", "notifications", "informational", "debugging"] + state: + description: + - Existential state of the logging configuration on the node. + choices: + - present + - absent + type: str + state: + description: + - Existential state of the logging configuration on the node. + default: present + choices: + - present + - absent + type: str +extends_documentation_fragment: +- cisco.iosxr.iosxr +""" + +EXAMPLES = """ +- name: configure logging for syslog server host + cisco.iosxr.iosxr_logging: + dest: host + name: 10.10.10.1 + level: critical + state: present + +- name: add hostnameprefix configuration + cisco.iosxr.iosxr_logging: + hostnameprefix: host1 + state: absent + +- name: add facility configuration + cisco.iosxr.iosxr_logging: + facility: local1 + state: present + +- name: configure console logging level + cisco.iosxr.iosxr_logging: + dest: console + level: debugging + state: present + +- name: configure monitor logging level + cisco.iosxr.iosxr_logging: + dest: monitor + level: errors + state: present + +- name: configure syslog to a file + cisco.iosxr.iosxr_logging: + dest: file + name: file_name + size: 2048 + level: errors + state: present + +- name: configure buffered logging with size + cisco.iosxr.iosxr_logging: + dest: buffered + size: 5100000 + +- name: Configure logging using aggregate + cisco.iosxr.iosxr_logging: + aggregate: + - {dest: console, level: warning} + - {dest: buffered, size: 4800000} + - {dest: file, name: file3, size: 2048} + - {dest: host, name: host3, level: critical} + +- name: Delete logging using aggregate + cisco.iosxr.iosxr_logging: + aggregate: + - {dest: console, level: warning} + - {dest: buffered, size: 4800000} + - {dest: file, name: file3, size: 2048} + - {dest: host, name: host3, level: critical} + state: absent +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always (empty list when no commands to send) + type: list + sample: + - logging 10.10.10.1 vrf default severity debugging + - logging facility local7 + - logging hostnameprefix host1 + - logging console critical + - logging buffered 2097153 + - logging buffered warnings + - logging monitor errors + - logging file log_file maxfilesize 1024 severity info +xml: + description: NetConf rpc xml sent to device with transport C(netconf) + returned: always (empty list when no xml rpc to send) + type: list + sample: + - '<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <syslog xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-syslog-cfg"> + <files> + <file xc:operation="delete"> + <file-name>file1</file-name> + <file-log-attributes> + <max-file-size>2097152</max-file-size> + <severity>2</severity> + </file-log-attributes> + </file> + </files> + </syslog> + </config>' +""" + +import collections +import re + +from copy import deepcopy + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + build_xml, + etree_find, + etree_findall, + get_capabilities, + get_config, + get_os_version, + is_cliconf, + is_netconf, + load_config, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import Version + + +severity_level = { + "emergency": "0", + "alert": "1", + "critical": "2", + "error": "3", + "warning": "4", + "notice": "5", + "info": "6", + "debug": "7", + "disable": "15", +} + +severity_transpose = { + "emergencies": "emergency", + "alerts": "alert", + "critical": "critical", + "errors": "error", + "warning": "warning", + "notifications": "notice", + "informational": "info", + "debugging": "debug", +} + + +class ConfigBase(object): + def __init__(self, module): + self._flag = None + self._module = module + self._result = {"changed": False, "warnings": []} + self._want = list() + self._have = list() + + def validate_size(self, value, type=None): + if value: + if type == "buffer": + if value and not int(307200) <= value <= int(125000000): + self._module.fail_json( + msg="buffer size must be between 307200 and 125000000", + ) + elif type == "file": + if value and not int(1) <= value <= int(2097152): + self._module.fail_json( + msg="file size must be between 1 and 2097152", + ) + return value + + def map_params_to_obj(self, required_if=None): + aggregate = self._module.params.get("aggregate") + if aggregate: + for item in aggregate: + for key in item: + if item.get(key) is None: + item[key] = self._module.params[key] + + d = item.copy() + + if d["dest"] not in ("host", "file"): + d["name"] = None + + if d["dest"] == "buffered": + if d["size"] is not None: + d["size"] = str( + self.validate_size(d["size"], "buffer"), + ) + else: + d["size"] = str(307200) + elif d["dest"] == "file": + if d["size"] is not None: + d["size"] = str(self.validate_size(d["size"], "file")) + else: + d["size"] = str(2097152) + else: + d["size"] = None + + if self._flag == "NC": + d["level"] = severity_transpose[d["level"]] + + self._want.append(d) + + else: + params = self._module.params + if params["dest"] not in ("host", "file"): + params["name"] = None + + if params["dest"] == "buffered": + if params["size"] is not None: + params["size"] = str( + self.validate_size(params["size"], "buffer"), + ) + else: + params["size"] = str(307200) + elif params["dest"] == "file": + if params["size"] is not None: + params["size"] = str( + self.validate_size(params["size"], "file"), + ) + else: + params["size"] = str(2097152) + else: + params["size"] = None + + if self._flag == "NC": + params["level"] = severity_transpose[params["level"]] + + self._want.append( + { + "dest": params["dest"], + "name": params["name"], + "vrf": params["vrf"], + "size": params["size"], + "path": params["path"], + "facility": params["facility"], + "level": params["level"], + "hostnameprefix": params["hostnameprefix"], + "state": params["state"], + }, + ) + + +class CliConfiguration(ConfigBase): + def __init__(self, module): + super(CliConfiguration, self).__init__(module) + self._file_list = set() + self._host_list = set() + + def map_obj_to_commands(self, os_version): + commands = list() + for want_item in self._want: + dest = want_item["dest"] + name = want_item["name"] + size = want_item["size"] + path = want_item["path"] + facility = want_item["facility"] + level = want_item["level"] + vrf = want_item["vrf"] + hostnameprefix = want_item["hostnameprefix"] + state = want_item["state"] + del want_item["state"] + + have_size = None + have_console_level = None + have_monitor_level = None + have_prefix = None + have_facility = None + + for item in self._have: + if item["dest"] == "buffered": + have_size = item["size"] + if item["dest"] == "console": + have_console_level = item["level"] + if item["dest"] == "monitor": + have_monitor_level = item["level"] + if item["dest"] is None and item["hostnameprefix"] is not None: + have_prefix = item["hostnameprefix"] + if ( + item["dest"] is None + and item["hostnameprefix"] is None + and item["facility"] is not None + ): + have_facility = item["facility"] + + if state == "absent": + if dest == "host" and name in self._host_list: + commands.append("no logging {0} vrf {1}".format(name, vrf)) + elif dest == "file" and name in self._file_list: + commands.append("no logging file {0}".format(name)) + elif dest == "console" and have_console_level is not None: + commands.append("no logging {0}".format(dest)) + elif dest == "monitor" and have_monitor_level: + commands.append("no logging {0}".format(dest)) + elif dest == "buffered" and have_size: + commands.append("no logging {0}".format(dest)) + + if dest is None and hostnameprefix is not None and have_prefix == hostnameprefix: + commands.append( + "no logging hostnameprefix {0}".format(hostnameprefix), + ) + if dest is None and facility is not None and have_facility == facility: + commands.append("no logging facility {0}".format(facility)) + + if state == "present": + if dest == "host" and name not in self._host_list: + if level == "errors" or level == "informational": + level = severity_transpose[level] + commands.append( + "logging {0} vrf {1} severity {2}".format( + name, + vrf, + level, + ), + ) + elif dest == "file" and name not in self._file_list: + if level == "errors" or level == "informational": + level = severity_transpose[level] + if os_version and Version(os_version) > Version("7.0"): + commands.append( + "logging file {0} path {1} maxfilesize {2} severity {3}".format( + name, + path, + size, + level, + ), + ) + else: + commands.append( + "logging file {0} maxfilesize {1} severity {2}".format( + name, + size, + level, + ), + ) + elif dest == "buffered" and ( + have_size is None or (have_size is not None and size != have_size) + ): + commands.append("logging buffered {0}".format(size)) + elif dest == "console" and ( + have_console_level is None + or (have_console_level is not None and have_console_level != level) + ): + commands.append("logging console {0}".format(level)) + elif dest == "monitor" and ( + have_monitor_level is None + or (have_monitor_level is not None and have_monitor_level != level) + ): + commands.append("logging monitor {0}".format(level)) + + if ( + dest is None + and hostnameprefix is not None + and ( + have_prefix is None + or (have_prefix is not None and hostnameprefix != have_prefix) + ) + ): + commands.append( + "logging hostnameprefix {0}".format(hostnameprefix), + ) + if dest is None and hostnameprefix is None and facility != have_facility: + commands.append("logging facility {0}".format(facility)) + + self._result["commands"] = commands + if commands: + commit = not self._module.check_mode + diff = load_config(self._module, commands, commit=commit) + if diff: + self._result["diff"] = dict(prepared=diff) + self._result["changed"] = True + + def parse_facility(self, line): + match = re.search(r"logging facility (\S+)", line, re.M) + facility = None + if match: + facility = match.group(1) + + return facility + + def parse_size(self, line, dest): + size = None + + if dest == "buffered": + match = re.search(r"logging buffered (\S+)", line, re.M) + if match: + try: + int_size = int(match.group(1)) + except ValueError: + int_size = None + + if int_size is not None: + if isinstance(int_size, int): + size = str(match.group(1)) + if dest == "file": + match = re.search( + r"logging file (\S+) (path\s\S+\s)?maxfilesize (\S+)", + line, + re.M, + ) + if match: + try: + if "path" in line: + int_size = int(match.group(2)) + else: + int_size = int(match.group(1)) + except ValueError: + int_size = None + + if int_size is not None: + if isinstance(int_size, int): + size = str(int_size) + + return size + + def parse_path(self, line, dest): + path = None + + if dest == "file": + match = re.search(r"logging file (\S+) (path\s\S+\s)", line, re.M) + if match: + try: + path = to_text( + match.group(2), + errors="surrogate_or_strict", + ) + except ValueError: + path = None + + return path + + def parse_hostnameprefix(self, line): + prefix = None + match = re.search(r"logging hostnameprefix (\S+)", line, re.M) + if match: + prefix = match.group(1) + return prefix + + def parse_name(self, line, dest): + name = None + if dest == "file": + match = re.search(r"logging file (\S+)", line, re.M) + if match: + name = match.group(1) + elif dest == "host": + match = re.search(r"logging (\S+)", line, re.M) + if match: + name = match.group(1) + + return name + + def parse_level(self, line, dest): + level_group = ( + "emergencies", + "alerts", + "critical", + "errors", + "warning", + "notifications", + "informational", + "debugging", + ) + + level = None + match = re.search(r"logging {0} (\S+)".format(dest), line, re.M) + if match: + if match.group(1) in level_group: + level = match.group(1) + + return level + + def parse_dest(self, line, group): + dest_group = ("console", "monitor", "buffered", "file") + dest = None + if group in dest_group: + dest = group + elif "vrf" in line: + dest = "host" + + return dest + + def parse_vrf(self, line, dest): + vrf = None + if dest == "host": + match = re.search(r"logging (\S+) vrf (\S+)", line, re.M) + if match: + vrf = match.group(2) + return vrf + + def map_config_to_obj(self): + data = get_config(self._module, config_filter="logging") + lines = data.split("\n") + + for line in lines: + match = re.search(r"logging (\S+)", line, re.M) + if match: + dest = self.parse_dest(line, match.group(1)) + name = self.parse_name(line, dest) + if dest == "host" and name is not None: + self._host_list.add(name) + if dest == "file" and name is not None: + self._file_list.add(name) + + self._have.append( + { + "dest": dest, + "name": name, + "size": self.parse_size(line, dest), + "path": self.parse_path(line, dest), + "facility": self.parse_facility(line), + "level": self.parse_level(line, dest), + "vrf": self.parse_vrf(line, dest), + "hostnameprefix": self.parse_hostnameprefix(line), + }, + ) + + def run(self, os_version): + self.map_params_to_obj() + self.map_config_to_obj() + self.map_obj_to_commands(os_version) + + return self._result + + +class NCConfiguration(ConfigBase): + def __init__(self, module): + super(NCConfiguration, self).__init__(module) + self._flag = "NC" + self._log_file_meta = collections.OrderedDict() + self._log_host_meta = collections.OrderedDict() + self._log_console_meta = collections.OrderedDict() + self._log_monitor_meta = collections.OrderedDict() + self._log_buffered_meta = collections.OrderedDict() + self._log_facility_meta = collections.OrderedDict() + self._log_prefix_meta = collections.OrderedDict() + + def map_obj_to_xml_rpc(self, os_version): + file_attribute_path = "file-log-attributes" + if os_version and Version(os_version) > Version("7.0.0"): + file_attribute_path = "file-specification" + self._log_file_meta.update( + [ + ( + "files", + { + "xpath": "syslog/files", + "tag": True, + "operation": "edit", + }, + ), + ( + "file", + { + "xpath": "syslog/files/file", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:name", + { + "xpath": "syslog/files/file/file-name", + "operation": "edit", + }, + ), + ( + "file-attrib", + { + "xpath": "syslog/files/file/" + file_attribute_path, + "tag": True, + "operation": "edit", + }, + ), + ( + "a:size", + { + "xpath": "syslog/files/file/" + file_attribute_path + "/max-file-size", + "operation": "edit", + }, + ), + ( + "a:level", + { + "xpath": "syslog/files/file/" + file_attribute_path + "/severity", + "operation": "edit", + }, + ), + ( + "a:path", + { + "xpath": "syslog/files/file/" + file_attribute_path + "/path", + "operation": "edit", + }, + ), + ], + ) + else: + self._log_file_meta.update( + [ + ( + "files", + { + "xpath": "syslog/files", + "tag": True, + "operation": "edit", + }, + ), + ( + "file", + { + "xpath": "syslog/files/file", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:name", + { + "xpath": "syslog/files/file/file-name", + "operation": "edit", + }, + ), + ( + "file-attrib", + { + "xpath": "syslog/files/file/" + file_attribute_path, + "tag": True, + "operation": "edit", + }, + ), + ( + "a:size", + { + "xpath": "syslog/files/file/" + file_attribute_path + "/max-file-size", + "operation": "edit", + }, + ), + ( + "a:level", + { + "xpath": "syslog/files/file/" + file_attribute_path + "/severity", + "operation": "edit", + }, + ), + ], + ) + self._log_host_meta.update( + [ + ( + "host-server", + { + "xpath": "syslog/host-server", + "tag": True, + "operation": "edit", + }, + ), + ( + "vrfs", + { + "xpath": "syslog/host-server/vrfs", + "tag": True, + "operation": "edit", + }, + ), + ( + "vrf", + { + "xpath": "syslog/host-server/vrfs/vrf", + "tag": True, + "operation": "edit", + }, + ), + ( + "a:vrf", + { + "xpath": "syslog/host-server/vrfs/vrf/vrf-name", + "operation": "edit", + }, + ), + ( + "ipv4s", + { + "xpath": "syslog/host-server/vrfs/vrf/ipv4s", + "tag": True, + "operation": "edit", + }, + ), + ( + "ipv4", + { + "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:name", + { + "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/address", + "operation": "edit", + }, + ), + ( + "ipv4-sev", + { + "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/ipv4-severity-port", + "tag": True, + "operation": "edit", + }, + ), + ( + "a:level", + { + "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/ipv4-severity-port/severity", + "operation": "edit", + }, + ), + ], + ) + self._log_console_meta.update( + [ + ( + "a:enable-console", + { + "xpath": "syslog/enable-console-logging", + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "console", + { + "xpath": "syslog/console-logging", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:console-level", + { + "xpath": "syslog/console-logging/logging-level", + "operation": "edit", + }, + ), + ], + ) + self._log_monitor_meta.update( + [ + ( + "monitor", + { + "xpath": "syslog/monitor-logging", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:monitor-level", + { + "xpath": "syslog/monitor-logging/logging-level", + "operation": "edit", + }, + ), + ], + ) + self._log_buffered_meta.update( + [ + ( + "buffered", + { + "xpath": "syslog/buffered-logging", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:size", + { + "xpath": "syslog/buffered-logging/buffer-size", + "operation": "edit", + }, + ), + ( + "a:level", + { + "xpath": "syslog/buffered-logging/logging-level", + "operation": "edit", + }, + ), + ], + ) + self._log_facility_meta.update( + [ + ( + "facility", + { + "xpath": "syslog/logging-facilities", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:facility", + { + "xpath": "syslog/logging-facilities/facility-level", + "operation": "edit", + }, + ), + ], + ) + self._log_prefix_meta.update( + [ + ( + "a:hostnameprefix", + { + "xpath": "syslog/host-name-prefix", + "operation": "edit", + "attrib": "operation", + }, + ), + ], + ) + + state = self._module.params["state"] + + _get_filter = build_xml("syslog", opcode="filter") + running = get_config( + self._module, + source="running", + config_filter=_get_filter, + ) + + file_ele = etree_findall(running, "file") + file_list = list() + if len(file_ele): + for file in file_ele: + file_name = etree_find(file, "file-name") + file_list.append( + file_name.text if file_name is not None else None, + ) + vrf_ele = etree_findall(running, "vrf") + host_list = list() + for vrf in vrf_ele: + host_ele = etree_findall(vrf, "ipv4") + for host in host_ele: + host_name = etree_find(host, "address") + host_list.append( + host_name.text if host_name is not None else None, + ) + + console_ele = etree_find(running, "console-logging") + console_level = ( + etree_find(console_ele, "logging-level") if console_ele is not None else None + ) + have_console = console_level.text if console_level is not None else None + + monitor_ele = etree_find(running, "monitor-logging") + monitor_level = ( + etree_find(monitor_ele, "logging-level") if monitor_ele is not None else None + ) + have_monitor = monitor_level.text if monitor_level is not None else None + + buffered_ele = etree_find(running, "buffered-logging") + buffered_size = ( + etree_find(buffered_ele, "buffer-size") if buffered_ele is not None else None + ) + have_buffered = buffered_size.text if buffered_size is not None else None + + facility_ele = etree_find(running, "logging-facilities") + facility_level = ( + etree_find(facility_ele, "facility-level") if facility_ele is not None else None + ) + have_facility = facility_level.text if facility_level is not None else None + + prefix_ele = etree_find(running, "host-name-prefix") + have_prefix = prefix_ele.text if prefix_ele is not None else None + + file_params = list() + host_params = list() + console_params = dict() + monitor_params = dict() + buffered_params = dict() + facility_params = dict() + prefix_params = dict() + + opcode = None + if state == "absent": + opcode = "delete" + for item in self._want: + if item["dest"] == "file" and item["name"] in file_list: + item["level"] = severity_level[item["level"]] + file_params.append(item) + elif item["dest"] == "host" and item["name"] in host_list: + item["level"] = severity_level[item["level"]] + host_params.append(item) + elif item["dest"] == "console" and have_console: + console_params.update({"console-level": item["level"]}) + elif item["dest"] == "monitor" and have_monitor: + monitor_params.update({"monitor-level": item["level"]}) + elif item["dest"] == "buffered" and have_buffered: + buffered_params["size"] = str(item["size"]) if item["size"] else None + buffered_params["level"] = item["level"] if item["level"] else None + elif ( + item["dest"] is None + and item["hostnameprefix"] is None + and item["facility"] is not None + and have_facility + ): + facility_params.update({"facility": item["facility"]}) + elif item["dest"] is None and item["hostnameprefix"] is not None and have_prefix: + prefix_params.update( + {"hostnameprefix": item["hostnameprefix"]}, + ) + elif state == "present": + opcode = "merge" + for item in self._want: + if item["dest"] == "file": + item["level"] = severity_level[item["level"]] + file_params.append(item) + elif item["dest"] == "host": + item["level"] = severity_level[item["level"]] + host_params.append(item) + elif item["dest"] == "console": + console_params.update({"console-level": item["level"]}) + elif item["dest"] == "monitor": + monitor_params.update({"monitor-level": item["level"]}) + elif item["dest"] == "buffered": + buffered_params["size"] = str(item["size"]) if item["size"] else None + buffered_params["level"] = item["level"] if item["level"] else None + elif ( + item["dest"] is None + and item["hostnameprefix"] is None + and item["facility"] is not None + ): + facility_params.update({"facility": item["facility"]}) + elif item["dest"] is None and item["hostnameprefix"] is not None: + prefix_params.update( + {"hostnameprefix": item["hostnameprefix"]}, + ) + + self._result["xml"] = [] + _edit_filter_list = list() + if opcode: + if len(file_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_file_meta, + params=file_params, + opcode=opcode, + ), + ) + if len(host_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_host_meta, + params=host_params, + opcode=opcode, + ), + ) + if len(console_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_console_meta, + params=console_params, + opcode=opcode, + ), + ) + if len(monitor_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_monitor_meta, + params=monitor_params, + opcode=opcode, + ), + ) + if len(buffered_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_buffered_meta, + params=buffered_params, + opcode=opcode, + ), + ) + if len(facility_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_facility_meta, + params=facility_params, + opcode=opcode, + ), + ) + if len(prefix_params): + _edit_filter_list.append( + build_xml( + "syslog", + xmap=self._log_prefix_meta, + params=prefix_params, + opcode=opcode, + ), + ) + + diff = None + if len(_edit_filter_list): + commit = not self._module.check_mode + diff = load_config( + self._module, + _edit_filter_list, + commit=commit, + running=running, + nc_get_filter=_get_filter, + ) + if diff: + if self._module._diff: + self._result["diff"] = dict(prepared=diff) + + self._result["xml"] = _edit_filter_list + self._result["changed"] = True + + def run(self, os_version): + self.map_params_to_obj() + self.map_obj_to_xml_rpc(os_version) + + return self._result + + +def main(): + """main entry point for module execution""" + element_spec = dict( + dest=dict( + type="str", + choices=["host", "console", "monitor", "buffered", "file"], + ), + name=dict(type="str"), + size=dict(type="int"), + path=dict(type="str"), + vrf=dict(type="str", default="default"), + facility=dict(type="str", default="local7"), + hostnameprefix=dict(type="str"), + level=dict( + type="str", + default="debugging", + aliases=["severity"], + choices=[ + "emergencies", + "alerts", + "critical", + "errors", + "warning", + "notifications", + "informational", + "debugging", + ], + ), + state=dict(default="present", choices=["present", "absent"]), + ) + + aggregate_spec = deepcopy(element_spec) + + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + + mutually_exclusive = [("dest", "facility", "hostnameprefix")] + + required_if = [ + ("dest", "host", ["name"]), + ("dest", "file", ["name"]), + ("dest", "buffered", ["size"]), + ("dest", "console", ["level"]), + ("dest", "monitor", ["level"]), + ] + + argument_spec = dict( + aggregate=dict( + type="list", + elements="dict", + options=aggregate_spec, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + ), + ) + + argument_spec.update(element_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + supports_check_mode=True, + ) + config_object = None + if is_cliconf(module): + config_object = CliConfiguration(module) + os_version = get_os_version(module) + elif is_netconf(module): + config_object = NCConfiguration(module) + os_version = get_capabilities(module).get("device_info").get("network_os_version") + + if config_object: + result = config_object.run(os_version) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging_global.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging_global.py new file mode 100644 index 00000000..4d25dcaa --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging_global.py @@ -0,0 +1,1407 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_logging_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_logging_global +version_added: 2.4.0 +short_description: Resource module to configure logging. +description: This module manages the logging attributes of Cisco IOSXR network devices +notes: +- Tested against IOSXR 7.0.2. +- This module works with connection C(network_cli). +author: Ashwini Mhatre (@amhatre) +options: + config: + description: A dictionary of logging options. + type: dict + suboptions: + archive: + description: logging to a persistent device(disk/harddisk) + type: dict + suboptions: + device: + type: str + description: Configure the archive device + archive_length: + type: int + description: The maximum no of weeks of log to maintain. + archive_size: + type: int + description: The total size of the archive. + file_size: + type: int + description: The maximum file size for a single log file.. + frequency: + type: str + description: The collection interval for logs. + choices: ["daily", "weekly"] + severity: &severity + description: Logging severity level + type: str + choices: + - alerts + - critical + - debugging + - emergencies + - errors + - informational + - notifications + - warnings + threshold: + type: int + description: Threshold percent <1-99>. + buffered: + description: Set buffered logging parameters + type: dict + suboptions: + size: &size + description: Logging buffer size + type: int + severity: *severity + discriminator: &discriminator + description: Establish MD-Buffer association + type: list + elements: dict + suboptions: + match_params: + type: str + description: Set match/no-match discriminator. + choices: ["match1", "match2", "match3", "nomatch1", "nomatch2", "nomatch3"] + name: + type: str + description: discriminator name. + console: + description: Set console logging parameters + type: dict + suboptions: + state: &state + description: Enable or disable logging. + type: str + choices: [ "enabled", "disabled" ] + severity: &severity1 + description: Logging severity level + type: str + choices: + - alerts + - critical + - debugging + - emergencies + - errors + - informational + - notifications + - warning + discriminator: *discriminator + correlator: + description: Configure properties of the event correlator + type: dict + suboptions: + buffer_size: + type: int + description: Configure size of the correlator buffer. + rules: + type: list + elements: dict + description: Configure a specified correlation rule. + suboptions: + rule_name: + type: str + description: name of rule. + rule_type: + type: str + choices: ["stateful", "nonstateful"] + description: type of rule - stateful or nonstateful. + timeout: + type: int + description: Specify timeout. + timeout_rootcause: + type: int + description: Specify timeout for root-cause. + context_correlation: + type: bool + description: Specify enable correlation on context. + reissue_nonbistate: + type: bool + description: Specify reissue of non-bistate alarms on parent clear.This option is allowed for the rules whose type is stateful. + reparent: + type: bool + description: Specify reparent of alarm on parent clear.This option is allowed for the rules whose type is stateful. + rule_sets: + type: list + elements: dict + description: Configure a specified correlation ruleset. + suboptions: + name: + type: str + description: Name of the ruleset + rulename: + type: list + elements: str + description: Name of the rule + events: + type: dict + description: Configure event monitoring parameters. + suboptions: + buffer_size: + type: int + description: Set size of the local event buffer. + display_location: + type: bool + description: Include alarm source location in message text. + filter_match: + type: list + elements: str + description: Configure filter. + severity: *severity + threshold: + type: int + description: Capacity alarm threshold. + facility: + description: Facility parameter for syslog messages + type: str + choices: + - auth + - cron + - daemon + - kern + - local0 + - local1 + - local2 + - local3 + - local4 + - local5 + - local6 + - local7 + - lpr + - mail + - news + - sys10 + - sys11 + - sys12 + - sys13 + - sys14 + - sys9 + - syslog + - user + - uucp + files: + type: list + elements: dict + description: Set file logging. + suboptions: + name: + description: name of file. + type: str + path: + description: Set file path. + type: str + maxfilesize: + type: int + description: Set max file size. + severity: + description: Logging severity level + type: str + choices: + - alerts + - critical + - debugging + - emergencies + - errors + - info + - notifications + - warning + format: + type: bool + description: Enable to send the syslog message rfc5424 format . + history: + description: Configure syslog history table + type: dict + suboptions: + state: *state + size: *size + severity: + description: Logging severity level + type: str + choices: + - alerts + - critical + - debugging + - emergencies + - errors + - informational + - notifications + - warnings + hostnameprefix: + type: str + description: Hostname prefix to add on msgs to servers. + ipv4: &ip + description: Mark the dscp/precedence bit for ipv4 packets. + type: dict + suboptions: + dscp: + description: Set IP DSCP (DiffServ CodePoint).Please refer vendor document for valid entries. + type: str + precedence: + description: Set precedence Please refer vendor document for valid entries. + type: str + ipv6: *ip + localfilesize: + type: int + description: Set size of the local log file + monitor: + description: Set terminal line (monitor) logging parameters + type: dict + suboptions: + state: *state + discriminator: *discriminator + severity: *severity1 + source_interfaces: + description: Specify interface for source address in logging transactions + type: list + elements: dict + suboptions: + interface: + description: Interface name with number + type: str + vrf: + description: VPN Routing/Forwarding instance name + type: str + suppress: + type: dict + description: Suppress logging behaviour. + suboptions: + apply_rule: + type: str + description: Apply suppression rule. + duplicates: + type: bool + description: Suppress consecutive duplicate messages. + tls_servers: + type: list + elements: dict + description: Secure server over tls. + suboptions: + name: + type: str + description: Name for the tls peer configuration. + severity: *severity + tls_hostname: + type: str + description: Name of the logging host. + trustpoint: + type: str + description: Name of the trustpoint configured. + vrf: + type: str + description: name of vrf. + trap: + description: Set syslog server logging level + type: dict + suboptions: + state: *state + severity: *severity1 + hosts: + description: Set syslog server IP address and parameters + type: list + elements: dict + suboptions: + severity: + description: Logging severity level + type: str + choices: + - alerts + - critical + - debugging + - emergencies + - error + - info + - notifications + - warning + host: + description: IPv4/Ipv6 address or hostname of the syslog server + type: str + port: + description: Set <0-65535> non-default Port. + type: str + default: default + vrf: + description: Set VRF option + type: str + default: default + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS device by + executing the command B(show running-config | include logging). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + description: + - The state the configuration should be left in + type: str +""" +EXAMPLES = """ +# Using merged +#----------------- +# Before state +#RP/0/0/CPU0:10#show running-config logging +#Thu Feb 4 09:38:36.245 UTC +#% No such configuration item(s) +#RP/0/0/CPU0:10# +# +# +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_logging_global: + config: + buffered: + size: 2097152 + severity: warnings + correlator: + buffer_size: 1024 + events: + display_location: True + files: + - maxfilesize: '1024' + name: test + path: test + severity: info + hostnameprefix: test + hosts: + - host: 1.1.1.1 + port: default + severity: critical + vrf: default + ipv4: + dscp: af11 + localfilesize: 1024 + monitor: + severity: errors + source_interfaces: + - interface: GigabitEthernet0/0/0/0 + vrf: test + tls_servers: + - name: test + tls_hostname: test2 + trustpoint: test2 + vrf: test + trap: + severity: informational + state: merged +# +# +# After state: +#------------------------------------------- +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:09:18.491 UTC +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +#------------------------------------------------ +#Module execution +# +# "after": { +# "buffered": { +# "severity": "errors" +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test1", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test1", +# "hosts": [ +# { +# "host": "1.1.1.3", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv6": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test1" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test", +# "vrf": "test" +# } +# ] +# }, +# "before": {}, +# "changed": true, +# "commands": [ +# "logging buffered errors", +# "logging correlator buffer-size 1024", +# "logging hostnameprefix test1", +# "logging ipv6 dscp af11", +# "logging localfilesize 1024", +# "logging trap disable", +# "logging monitor disable", +# "logging history disable", +# "logging console disable", +# "logging 1.1.1.3 vrf default severity critical port default", +# "logging file test path test1 maxfilesize 1024 severity info", +# "logging source-interface GigabitEthernet0/0/0/0 vrf test1", +# "logging tls-server test tls-hostname test2", +# "logging tls-server test trustpoint test", +# "logging tls-server test vrf test" +# ], +# "invocation": { +# "module_args": { +# "config": { +# "archive": null, +# "buffered": { +# "discriminator": null, +# "severity": "errors", +# "size": null +# }, +# "console": { +# "discriminator": null, +# "severity": null, +# "state": "disabled" +# }, +# "correlator": { +# "buffer_size": 1024, +# "rule_set": null, +# "rules": null +# }, +# "events": null, +# "facility": null, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test1", +# "severity": "info" +# } +# ], +# "format": null, +# "history": { +# "severity": null, +# "size": null, +# "state": "disabled" +# }, +# "hostnameprefix": "test1", +# "hosts": [ +# { +# "host": "1.1.1.3", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": null, +# "ipv6": { +# "dscp": "af11", +# "precedence": null +# }, +# "localfilesize": 1024, +# "monitor": { +# "discriminator": null, +# "severity": null, +# "state": "disabled" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test1" +# } +# ], +# "suppress": null, +# "tls_servers": [ +# { +# "name": "test", +# "severity": null, +# "tls_hostname": "test2", +# "trustpoint": "test", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": null, +# "state": "disabled" +# } +# }, +# "running_config": null, +# "state": "merged" +# } +# } +# } +# +# Using replaced: +# ----------------------------------------------------------- +# +#Before state +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:09:18.491 UTC +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +#----------------------------------------------------------- +# +- name: Replace BGP configuration with provided configuration + cisco.iosxr.iosxr_logging_global: + state: replaced + config: + buffered: + severity: errors + correlator: + buffer_size: 1024 + files: + - maxfilesize: '1024' + name: test + path: test1 + severity: info + hostnameprefix: test1 + hosts: + - host: 1.1.1.3 + port: default + severity: critical + vrf: default + ipv6: + dscp: af11 + localfilesize: 1024 + monitor: + severity: errors + tls_servers: + - name: test + tls_hostname: test2 + trustpoint: test + vrf: test + trap: + severity: critical +# +# After state: +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:31:51.709 UTC +# logging tls-server test +# vrf test +# trustpoint test +# tls-hostname test2 +# ! +# logging file test path test1 maxfilesize 1024 severity info +# logging ipv6 dscp af11 +# logging trap critical +# logging monitor errors +# logging buffered errors +# logging 1.1.1.3 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging hostnameprefix test1 +#----------------------------------------------------------------- +# +# Module Execution: +# "after": { +# "buffered": { +# "severity": "errors" +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test1", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test1", +# "hosts": [ +# { +# "host": "1.1.1.3", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv6": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "critical" +# } +# }, +# "before": { +# "buffered": { +# "severity": "warnings", +# "size": 2097152 +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "events": { +# "display_location": true +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test", +# "hosts": [ +# { +# "host": "1.1.1.1", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test2", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "informational" +# } +# }, +# "changed": true, +# "commands": [ +# "no logging buffered 2097152", +# "no logging events display-location", +# "no logging ipv4 dscp af11", +# "no logging 1.1.1.1 vrf default severity critical port default", +# "no logging source-interface GigabitEthernet0/0/0/0 vrf test", +# "logging buffered errors", +# "logging hostnameprefix test1", +# "logging ipv6 dscp af11", +# "logging trap critical", +# "logging 1.1.1.3 vrf default severity critical port default", +# "logging file test path test1 maxfilesize 1024 severity info", +# "logging tls-server test trustpoint test" +# ], +# +# +# +# Using deleted: +# ----------------------------------------------------------- +# Before state: +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:09:18.491 UTC +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +# +#----------------------------------------------------------- +- name: Delete given logging_global configuration + cisco.iosxr.iosxr_logging_global: + state: deleted +# +# After state: +#RP/0/0/CPU0:10#show running-config +# +#------------------------------------------------------------- +# Module Execution: +# +# "after": {}, +# "before": { +# "buffered": { +# "severity": "warnings", +# "size": 2097152 +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "events": { +# "display_location": true +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test", +# "hosts": [ +# { +# "host": "1.1.1.1", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test2", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "informational" +# } +# }, +# "changed": true, +# "commands": [ +# "no logging buffered 2097152", +# "no logging buffered warnings", +# "no logging correlator buffer-size 1024", +# "no logging events display-location", +# "no logging hostnameprefix test", +# "no logging ipv4 dscp af11", +# "no logging localfilesize 1024", +# "no logging monitor errors", +# "no logging trap informational", +# "no logging 1.1.1.1 vrf default severity critical port default", +# "no logging file test path test maxfilesize 1024 severity info", +# "no logging source-interface GigabitEthernet0/0/0/0 vrf test", +# "no logging tls-server test" +# ], +# "invocation": { +# "module_args": { +# "config": null, +# "running_config": null, +# "state": "deleted" +# } +# } +# +# +# +# using gathered: +# ------------------------------------------------------------ +# Before state: +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:09:18.491 UTC +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +# +# +- name: Gather iosxr_logging_global facts using gathered state + cisco.iosxr.iosxr_logging_global: + state: gathered +# +#------------------------------------------------------------- +# Module Execution: +# +# "changed": false, +# "gathered": { +# "buffered": { +# "severity": "warnings", +# "size": 2097152 +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "events": { +# "display_location": true +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test", +# "hosts": [ +# { +# "host": "1.1.1.1", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test2", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "informational" +# } +# }, +# "invocation": { +# "module_args": { +# "config": null, +# "running_config": null, +# "state": "gathered" +# } +# } +# +# +# Using parsed: +#--------------------------------------------------------------- +# +# parsed.cfg +# +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +# +# +- name: Parse externally provided Logging global config to agnostic model + cisco.iosxr.iosxr_logging_global: + running_config: "{{ lookup('file', './fixtures/parsed.cfg') }}" + state: parsed +#---------------------------------------------------------------- +# Module execution: +# "changed": false, +# "parsed": { +# "buffered": { +# "severity": "warnings", +# "size": 2097152 +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "events": { +# "display_location": true +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test", +# "hosts": [ +# { +# "host": "1.1.1.1", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test2", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "informational" +# } +# } +# +# +# Using rendered: +# ---------------------------------------------------------------------------- +- name: Render platform specific configuration lines with state rendered (without connecting to the device) + cisco.iosxr.iosxr_logging_global: + state: rendered + config: + buffered: + size: 2097152 + severity: warnings + correlator: + buffer_size: 1024 + events: + display_location: True + files: + - maxfilesize: '1024' + name: test + path: test + severity: info + hostnameprefix: test + hosts: + - host: 1.1.1.1 + port: default + severity: critical + vrf: default + ipv4: + dscp: af11 + localfilesize: 1024 + monitor: + severity: errors + source_interfaces: + - interface: GigabitEthernet0/0/0/0 + vrf: test + tls_servers: + - name: test + tls_hostname: test2 + trustpoint: test2 + vrf: test + trap: + severity: informational +#---------------------------------------------------------------- +# Module Execution: +# "rendered": [ +# "logging buffered errors", +# "logging correlator buffer-size 1024", +# "logging hostnameprefix test1", +# "logging ipv6 dscp af11", +# "logging localfilesize 1024", +# "logging trap disable", +# "logging monitor disable", +# "logging history disable", +# "logging console disable", +# "logging 1.1.1.3 vrf default severity critical port default", +# "logging file test path test1 maxfilesize 1024 severity info", +# "logging source-interface GigabitEthernet0/0/0/0 vrf test1", +# "logging tls-server test tls-hostname test2", +# "logging tls-server test trustpoint test", +# "logging tls-server test vrf test" +# ] +# +# Using overridden: +# --------------------------------------------------------------------------------- +# Before state: +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:09:18.491 UTC +# logging tls-server test +# vrf test +# trustpoint test2 +# tls-hostname test2 +# ! +# logging file test path test maxfilesize 1024 severity info +# logging ipv4 dscp af11 +# logging trap informational +# logging events display-location +# logging monitor errors +# logging buffered 2097152 +# logging buffered warnings +# logging 1.1.1.1 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging source-interface GigabitEthernet0/0/0/0 vrf test +# logging hostnameprefix test +# +#----------------------------------------------------------- +# +- name: Overridde logging global configuration with provided configuration + cisco.iosxr.iosxr_logging_global: + state: overridden + config: + buffered: + severity: errors + correlator: + buffer_size: 1024 + files: + - maxfilesize: '1024' + name: test + path: test1 + severity: info + hostnameprefix: test1 + hosts: + - host: 1.1.1.3 + port: default + severity: critical + vrf: default + ipv6: + dscp: af11 + localfilesize: 1024 + monitor: + severity: errors + tls_servers: + - name: test + tls_hostname: test2 + trustpoint: test + vrf: test + trap: + severity: critical +# +# After state: +#RP/0/0/CPU0:10#show running-config logging +# Tue Jul 20 18:31:51.709 UTC +# logging tls-server test +# vrf test +# trustpoint test +# tls-hostname test2 +# ! +# logging file test path test1 maxfilesize 1024 severity info +# logging ipv6 dscp af11 +# logging trap critical +# logging monitor errors +# logging buffered errors +# logging 1.1.1.3 vrf default severity critical port default +# logging correlator buffer-size 1024 +# logging localfilesize 1024 +# logging hostnameprefix test1 +#----------------------------------------------------------------- +# +# Module Execution: +# "after": { +# "buffered": { +# "severity": "errors" +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test1", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test1", +# "hosts": [ +# { +# "host": "1.1.1.3", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv6": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "critical" +# } +# }, +# "before": { +# "buffered": { +# "severity": "warnings", +# "size": 2097152 +# }, +# "correlator": { +# "buffer_size": 1024 +# }, +# "events": { +# "display_location": true +# }, +# "files": [ +# { +# "maxfilesize": "1024", +# "name": "test", +# "path": "test", +# "severity": "info" +# } +# ], +# "hostnameprefix": "test", +# "hosts": [ +# { +# "host": "1.1.1.1", +# "port": "default", +# "severity": "critical", +# "vrf": "default" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "localfilesize": 1024, +# "monitor": { +# "severity": "errors" +# }, +# "source_interfaces": [ +# { +# "interface": "GigabitEthernet0/0/0/0", +# "vrf": "test" +# } +# ], +# "tls_servers": [ +# { +# "name": "test", +# "tls_hostname": "test2", +# "trustpoint": "test2", +# "vrf": "test" +# } +# ], +# "trap": { +# "severity": "informational" +# } +# }, +# "changed": true, +# "commands": [ +# "no logging buffered 2097152", +# "no logging events display-location", +# "no logging ipv4 dscp af11", +# "no logging 1.1.1.1 vrf default severity critical port default", +# "no logging source-interface GigabitEthernet0/0/0/0 vrf test", +# "logging buffered errors", +# "logging hostnameprefix test1", +# "logging ipv6 dscp af11", +# "logging trap critical", +# "logging 1.1.1.3 vrf default severity critical port default", +# "logging file test path test1 maxfilesize 1024 severity info", +# "logging tls-server test trustpoint test" +# ], +# +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged) + type: list + sample: + - "logging file test path test1 maxfilesize 1024 severity info" + - "logging ipv6 dscp af11" + - "logging trap critical" + - "logging monitor errors" + - "logging buffered errors" + - "logging 1.1.1.3 vrf default severity critical port default" +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when state is I(rendered) + type: list + sample: + - "logging buffered errors" + - "logging correlator buffer-size 1024" + - "logging hostnameprefix test1" + - "logging ipv6 dscp af11" + - "logging localfilesize 1024" + - "logging trap disable" + - "logging monitor disable" + - "logging history disable" + - "logging console disable" +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when state is I(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when state is I(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.logging_global.logging_global import ( + Logging_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.logging_global.logging_global import ( + Logging_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Logging_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Logging_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_netconf.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_netconf.py new file mode 100644 index 00000000..e9a1c7c7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_netconf.py @@ -0,0 +1,206 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, Ansible by Red Hat, Inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_netconf +author: Kedar Kekan (@kedarX) +short_description: Configures NetConf sub-system service on Cisco IOS-XR devices +description: +- This module provides an abstraction that enables and configures the netconf system + service running on Cisco IOS-XR Software. This module can be used to easily enable + the Netconf API. Netconf provides a programmatic interface for working with configuration + and state resources as defined in RFC 6242. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.iosxr.iosxr +options: + netconf_port: + description: + - This argument specifies the port the netconf service should listen on for SSH + connections. The default port as defined in RFC 6242 is 830. + required: false + type: int + default: 830 + aliases: + - listens_on + netconf_vrf: + description: + - netconf vrf name + required: false + type: str + default: default + aliases: + - vrf + state: + description: + - Specifies the state of the C(iosxr_netconf) resource on the remote device. If + the I(state) argument is set to I(present) the netconf service will be configured. If + the I(state) argument is set to I(absent) the netconf service will be removed + from the configuration. + type: str + required: false + default: present + choices: + - present + - absent +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). +""" + +EXAMPLES = """ +- name: enable netconf service on port 830 + cisco.iosxr.iosxr_netconf: + listens_on: 830 + state: present + +- name: disable netconf service + cisco.iosxr.iosxr_netconf: + state: absent +""" + +RETURN = """ +commands: + description: Returns the command sent to the remote device + returned: when changed is True + type: str + sample: 'ssh server netconf port 830' +""" +import re + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import iteritems + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + get_config, + load_config, +) + + +USE_PERSISTENT_CONNECTION = True + + +def map_obj_to_commands(updates): + want, have = updates + commands = list() + + if want["state"] == "absent": + if have["state"] == "present": + commands.append("no netconf-yang agent ssh") + + if "netconf_port" in have: + commands.append("no ssh server netconf port %s" % have["netconf_port"]) + + if have["netconf_vrf"]: + for vrf in have["netconf_vrf"]: + commands.append("no ssh server netconf vrf %s" % vrf) + else: + if have["state"] == "absent": + commands.append("netconf-yang agent ssh") + + if want["netconf_port"] is not None and (want["netconf_port"] != have.get("netconf_port")): + commands.append("ssh server netconf port %s" % want["netconf_port"]) + if want["netconf_vrf"] is not None and (want["netconf_vrf"] not in have["netconf_vrf"]): + commands.append("ssh server netconf vrf %s" % want["netconf_vrf"]) + + return commands + + +def parse_vrf(config): + match = re.search(r"vrf (\w+)", config) + if match: + return match.group(1) + + +def parse_port(config): + match = re.search(r"port (\d+)", config) + if match: + return int(match.group(1)) + + +def map_config_to_obj(module): + obj = {"state": "absent"} + + netconf_config = get_config(module, config_filter="netconf-yang agent") + + ssh_config = get_config(module, config_filter="ssh server") + ssh_config = [ + config_line + for config_line in (line.strip() for line in ssh_config.splitlines()) + if config_line + ] + obj["netconf_vrf"] = [] + for config in ssh_config: + if "netconf port" in config: + obj.update({"netconf_port": parse_port(config)}) + if "netconf vrf" in config: + obj["netconf_vrf"].append(parse_vrf(config)) + if "ssh" in netconf_config and ("netconf_port" in obj or obj["netconf_vrf"]): + obj.update({"state": "present"}) + + if "ssh" in netconf_config and "netconf_port" not in obj: + obj.update({"netconf_port": 830}) + + return obj + + +def validate_netconf_port(value, module): + if not 1 <= value <= 65535: + module.fail_json(msg="netconf_port must be between 1 and 65535") + + +def map_params_to_obj(module): + obj = { + "netconf_port": module.params["netconf_port"], + "netconf_vrf": module.params["netconf_vrf"], + "state": module.params["state"], + } + + for key, value in iteritems(obj): + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if callable(validator): + validator(value, module) + + return obj + + +def main(): + """main entry point for module execution""" + argument_spec = dict( + netconf_port=dict(type="int", default=830, aliases=["listens_on"]), + netconf_vrf=dict(aliases=["vrf"], default="default"), + state=dict(default="present", choices=["present", "absent"]), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + warnings = list() + + result = {"changed": False, "warnings": warnings} + + want = map_params_to_obj(module) + have = map_config_to_obj(module) + commands = map_obj_to_commands((want, have)) + result["commands"] = commands + + if commands: + commit = not module.check_mode + diff = load_config(module, commands, commit=commit) + if diff: + result["diff"] = dict(prepared=diff) + result["changed"] = True + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ntp_global.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ntp_global.py new file mode 100644 index 00000000..94ca24f4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ntp_global.py @@ -0,0 +1,1096 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_ntp_global +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: iosxr_ntp_global +short_description: Resource module to configure NTP. +description: This module configures and manages the attributes of ntp on Cisco + IOSXR platforms. +version_added: 2.5.0 +author: Ashwini Mhatre (@amhatre) +notes: + - Tested against IOSXR 7.0.2. + - This module works with connection C(network_cli). +options: + config: + description: A dictionary of ntp options + type: dict + suboptions: + access_group: + description: Control NTP access + type: dict + suboptions: + ipv4: &ipv4 + type: dict + description: Configure IPv4 access + suboptions: + peer: &peer + type: str + description: Provide full access + query_only: &query_only + type: str + description: Allow only control queries. + serve: &serve + type: str + description: Provide server and query access. + serve_only: &serve_only + type: str + description: Provide only server access. + ipv6: &ipv6 + type: dict + description: Configure IPv6 access + suboptions: + peer: *peer + query_only: *query_only + serve: *serve + serve_only: *serve_only + vrfs: + type: list + elements: dict + description: Specify non-default VRF. + suboptions: + name: + type: str + description: Specify non-default VRF. + ipv4: *ipv4 + ipv6: *ipv6 + authenticate: + description: Authenticate time sources + type: bool + authentication_keys: + description: Authentication key for trusted time sources + type: list + elements: dict + suboptions: + id: + description: <1-65535> Key number + type: int + key: + description: Authentication key. + type: str + encryption: + description: Type of key encrypted or clear-text. + type: bool + broadcastdelay: + type: int + description: Estimated round-trip delay in microseconds. + drift: + type: dict + description: Drift(cisco-support) + suboptions: + aging_time: + type: int + description: Aging time in hours. + file: + description: File for drift values. + type: str + interfaces: + type: list + elements: dict + description: Configure NTP on an interface. + suboptions: + name: + type: str + description: Name of the interface. + vrf: + type: str + description: Name of the vrf. + broadcast_client: + type: bool + description: Listen to NTP broadcasts + broadcast_destination: + type: str + description: Configure broadcast destination address. + broadcast_key: + type: int + description: Broadcast key number. + broadcast_version: + type: int + description: <2-4> NTP version number. + multicast_key: + type: int + description: Configure multicast authentication key. + multicast_ttl: + type: int + description: Configure TTL to use. + multicast_client: + type: str + description: Configure multicast client + multicast_destination: + type: str + description: Configure multicast destination + multicast_version: + type: int + description: <2-4> NTP version number. + ipv4: &ip + description: Mark the dscp/precedence bit for ipv4 packets. + type: dict + suboptions: + dscp: + description: Set IP DSCP (DiffServ CodePoint).Please refer vendor document for valid entries. + type: str + precedence: + description: Set precedence Please refer vendor document for valid entries. + type: str + choices: [ "critical", "flash", "flash-override", "immediate", "internet", "network", "priority", "routine" ] + ipv6: *ip + log_internal_sync: + type: bool + description: Logs internal synchronization changes. + master: + description: Act as NTP master clock + type: dict + suboptions: + stratum: + description: Use NTP as clock source with stratum number <1-15> + type: int + max_associations: + type: int + description: <0-4294967295> Number of associations. + passive: + type: bool + description: Enable the passive associations. + trusted_keys: + type: list + elements: dict + description: list of Key numbers for trusted time sources. + suboptions: + key_id: + type: int + description: Key numbers for trusted time sources. + update_calendar: + type: bool + description: Periodically update calendar with NTP time. + source_interface: + type: str + description: Configure default interface. + source_vrfs: + type: list + elements: dict + description: Configure default interface. + suboptions: + name: + type: str + description: Name of source interface. + vrf: + type: str + description: vrf name. + servers: + description: Configure NTP server. + type: list + elements: dict + suboptions: + vrf: &vrf + description: vrf name. + type: str + server: &host + description: Hostname or A.B.C.D or A:B:C:D:E:F:G:H. + type: str + required: True + burst: &burst + description: Use burst mode. + type: bool + iburst: &iburst + description: Use initial burst mode. + type: bool + key_id: &key + description: SConfigure peer authentication key + type: int + source: &source + description: Interface for source address. + type: str + maxpoll: &maxpoll + description: configure Maximum poll interval. + type: int + minpoll: &minpoll + description: configure Minimum poll interval. + type: int + prefer: &prefer + description: Prefer this peer when possible + type: bool + version: &version + description: NTP version. + type: int + peers: + description: Configure NTP peer. + type: list + elements: dict + suboptions: + vrf: *vrf + peer: *host + burst: *burst + iburst: *iburst + key_id: *key + source: *source + maxpoll: *maxpoll + minpoll: *minpoll + prefer: *prefer + version: *version + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOSXR device by + executing the command B(show running-config ntp). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - deleted + - merged + - overridden + - replaced + - gathered + - rendered + - parsed + default: merged +""" + +EXAMPLES = """ +# Using state: merged +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config ntp +# --------------------- EMPTY ----------------- +# Merged play: +# ------------ +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_ntp_global: + config: + access_group: + ipv4: + peer: PeerAcl1 + query_only: QueryOnlyAcl1 + serve: ServeAcl1 + serve_only: ServeOnlyAcl1 + vrfs: + - ipv4: + peer: PeerAcl3 + serve: ServeAcl2 + name: siteA + authenticate: true + broadcastdelay: 1 + drift: + aging_time: 0 + file: apphost + interfaces: + - name: GigabitEthernet0/0/0/0 + multicast_client: 224.0.0.8 + multicast_destination: 224.0.0.8 + broadcast_client: true + ipv4: + dscp: af11 + ipv6: + precedence: routine + log_internal_sync: true + master: 1 + max_associations: 10 + passive: true + peers: + - iburst: true + peer: 192.0.2.1 + vrf: siteC + servers: + - burst: true + server: 192.0.2.2 + vrf: siteD + source: GigabitEthernet0/0/0/0 + source_vrfs: + - name: GigabitEthernet0/0/0/0 + vrf: siteE + trusted_keys: + - key_id: 1 + update_calendar: true +# Commands Fired: +# ------------ +# "commands": [ +# "ntp peer vrf siteC 192.0.2.1 iburst ", +# "ntp server vrf siteD 192.0.2.2 burst ", +# "ntp trusted-key 1", +# "ntp interface GigabitEthernet0/0/0/0 broadcast client", +# "ntp interface GigabitEthernet0/0/0/0 multicast destination 224.0.0.8", +# "ntp interface GigabitEthernet0/0/0/0 multicast client 224.0.0.8", +# "ntp vrf siteE source GigabitEthernet0/0/0/0", +# "ntp access-group vrf siteA ipv4 serve ServeAcl2", +# "ntp access-group vrf siteA ipv4 peer PeerAcl3", +# "ntp access-group ipv4 peer PeerAcl1", +# "ntp access-group ipv4 serve ServeAcl1", +# "ntp access-group ipv4 serve-only ServeOnlyAcl1", +# "ntp access-group ipv4 query-only QueryOnlyAcl1", +# "ntp authenticate", +# "ntp log-internal-sync", +# "ntp broadcastdelay 1", +# "ntp drift aging time 0", +# "ntp drift file apphost", +# "ntp ipv4 dscp af11", +# "ntp ipv6 precedence routine", +# "ntp max-associations 10", +# "ntp master 1", +# "ntp passive", +# "ntp update-calendar", +# "ntp source GigabitEthernet0/0/0/0" +# ], +# After state: +# ------------ +# RP/0/0/CPU0:10#show running-config ntp +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Using state: deleted +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config ntp +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Deleted play: +# ------------- +- name: Remove all existing configuration + cisco.iosxr.iosxr_ntp_global: + state: deleted +# Commands Fired: +# --------------- +# "commands": [ +# "no ntp peer vrf siteC 192.0.2.1 iburst ", +# "no ntp server vrf siteD 192.0.2.2 burst ", +# "no ntp trusted-key 1", +# "no ntp interface GigabitEthernet0/0/0/0", +# "no ntp vrf siteE source GigabitEthernet0/0/0/0", +# "no ntp access-group vrf siteA ipv4 serve ServeAcl2", +# "no ntp access-group vrf siteA ipv4 peer PeerAcl3", +# "no ntp access-group ipv4 peer PeerAcl1", +# "no ntp access-group ipv4 serve ServeAcl1", +# "no ntp access-group ipv4 serve-only ServeOnlyAcl1", +# "no ntp access-group ipv4 query-only QueryOnlyAcl1", +# "no ntp authenticate", +# "no ntp log-internal-sync", +# "no ntp broadcastdelay 1", +# "no ntp drift aging time 0", +# "no ntp drift file apphost", +# "no ntp ipv4 dscp af11", +# "no ntp ipv6 precedence routine", +# "no ntp max-associations 10", +# "no ntp master 1", +# "no ntp passive", +# "no ntp update-calendar", +# "no ntp source GigabitEthernet0/0/0/0" +# ], +# After state: +# ------------ +# RP/0/0/CPU0:10#show running-config ntp +# --------------------- EMPTY ----------------- +# Using state: overridden +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config ntp +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Overridden play: +# ---------------- +- name: Override BGP configuration with provided configuration + cisco.iosxr.iosxr_ntp_global: + state: overridden + config: + access_group: + ipv4: + peer: PeerAcl1 + query_only: QueryOnlyAcl1 + serve: ServeAcl4 + serve_only: ServeOnlyAcl1 + vrfs: + - ipv4: + peer: PeerAcl3 + serve: ServeAcl2 + name: siteA + authenticate: true + broadcastdelay: 1 + drift: + aging_time: 0 + file: apphost + interfaces: + - name: GigabitEthernet0/0/0/1 + multicast_client: 224.0.0.8 + multicast_destination: 224.0.0.8 + broadcast_client: true + ipv4: + dscp: af12 + ipv6: + precedence: routine + log_internal_sync: true + master: 1 + max_associations: 10 + passive: true + peers: + - iburst: true + peer: 192.0.2.3 + vrf: siteC + servers: + - burst: true + server: 192.0.2.2 + vrf: siteD + source: GigabitEthernet0/0/0/1 + source_vrfs: + - name: GigabitEthernet0/0/0/0 + vrf: siteE + trusted_keys: + - key_id: 1 + update_calendar: true +# Commands Fired: +# --------------- +# "commands": [ +# "no ntp peer vrf siteC 192.0.2.1 iburst ", +# "no ntp interface GigabitEthernet0/0/0/0", +# "ntp peer vrf siteC 192.0.2.3 iburst ", +# "ntp interface GigabitEthernet0/0/0/1 broadcast client", +# "ntp interface GigabitEthernet0/0/0/1 multicast destination 224.0.0.8", +# "ntp interface GigabitEthernet0/0/0/1 multicast client 224.0.0.8", +# "ntp access-group ipv4 serve ServeAcl4", +# "ntp ipv4 dscp af12", +# "ntp source GigabitEthernet0/0/0/1" +# ], +# After state: +# ------------ +# RP/0/RP0/CPU0:ios#show running-config ntp +# Mon Sep 13 10:38:22.690 UTC +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/1 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authentication-key 1 md5 encrypted testkey +# authenticate +# trusted-key 1 +# ipv4 dscp af12 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.3 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl4 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/1 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# +# Using state: replaced +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config ntp +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Replaced play: +# ---------------- +- name: Replaced BGP configuration with provided configuration + cisco.iosxr.iosxr_ntp_global: + state: replaced + config: + access_group: + ipv4: + peer: PeerAcl1 + query_only: QueryOnlyAcl1 + serve: ServeAcl4 + serve_only: ServeOnlyAcl1 + vrfs: + - ipv4: + peer: PeerAcl3 + serve: ServeAcl2 + name: siteA + authenticate: true + broadcastdelay: 1 + drift: + aging_time: 0 + file: apphost + interfaces: + - name: GigabitEthernet0/0/0/1 + multicast_client: 224.0.0.8 + multicast_destination: 224.0.0.8 + broadcast_client: true + ipv4: + dscp: af12 + ipv6: + precedence: routine + log_internal_sync: true + master: 1 + max_associations: 10 + passive: true + peers: + - iburst: true + peer: 192.0.2.3 + vrf: siteC + servers: + - burst: true + server: 192.0.2.2 + vrf: siteD + source: GigabitEthernet0/0/0/1 + source_vrfs: + - name: GigabitEthernet0/0/0/0 + vrf: siteE + trusted_keys: + - key_id: 1 + update_calendar: true +# Commands Fired: +# --------------- +# "commands": [ +# "no ntp peer vrf siteC 192.0.2.1 iburst ", +# "no ntp interface GigabitEthernet0/0/0/0", +# "ntp peer vrf siteC 192.0.2.3 iburst ", +# "ntp interface GigabitEthernet0/0/0/1 broadcast client", +# "ntp interface GigabitEthernet0/0/0/1 multicast destination 224.0.0.8", +# "ntp interface GigabitEthernet0/0/0/1 multicast client 224.0.0.8", +# "ntp access-group ipv4 serve ServeAcl4", +# "ntp ipv4 dscp af12", +# "ntp source GigabitEthernet0/0/0/1" +# ], +# After state: +# ------------ +# RP/0/RP0/CPU0:ios#show running-config ntp +# Mon Sep 13 10:38:22.690 UTC +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/1 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authentication-key 1 md5 encrypted testkey +# authenticate +# trusted-key 1 +# ipv4 dscp af12 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.3 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl4 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/1 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Using state: gathered +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config ntp +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Gathered play: +# -------------- +- name: Gather listed ntp config + cisco.iosxr.iosxr_ntp_global: + state: gathered +# Module Execution Result: +# ------------------------ +# "gathered":{ +# "access_group": { +# "ipv4": { +# "peer": "PeerAcl1", +# "query_only": "QueryOnlyAcl1", +# "serve": "ServeAcl1", +# "serve_only": "ServeOnlyAcl1" +# }, +# "vrfs": [ +# { +# "ipv4": { +# "peer": "PeerAcl3", +# "serve": "ServeAcl2" +# }, +# "name": "siteA" +# } +# ] +# }, +# "authenticate": true, +# "broadcastdelay": 1, +# "drift": { +# "aging_time": 0, +# "file": "apphost" +# }, +# "interfaces": [ +# { +# "broadcast_client": true, +# "multicast_client": "224.0.0.8", +# "multicast_destination": "224.0.0.8", +# "name": "GigabitEthernet0/0/0/0" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "ipv6": { +# "precedence": "routine" +# }, +# "log_internal_sync": true, +# "master": 1, +# "max_associations": 10, +# "passive": true, +# "peers": [ +# { +# "iburst": true, +# "peer": "192.0.2.1", +# "vrf": "siteC" +# } +# ], +# "servers": [ +# { +# "burst": true, +# "server": "192.0.2.2", +# "vrf": "siteD" +# } +# ], +# "source": "GigabitEthernet0/0/0/0", +# "source_vrfs": [ +# { +# "name": "GigabitEthernet0/0/0/0", +# "vrf": "siteE" +# } +# ], +# "trusted_keys": [ +# { +# "key_id": 1 +# } +# ], +# "update_calendar": true +# } +# Using state: rendered +# Rendered play: +# -------------- +- name: Render platform specific configuration lines with state rendered (without connecting to the device) + cisco.iosxr.iosxr_ntp_global: + state: rendered + config: + access_group: + ipv4: + peer: PeerAcl1 + query_only: QueryOnlyAcl1 + serve: ServeAcl1 + serve_only: ServeOnlyAcl1 + vrfs: + - ipv4: + peer: PeerAcl3 + serve: ServeAcl2 + name: siteA + authenticate: true + broadcastdelay: 1 + drift: + aging_time: 0 + file: apphost + interfaces: + - name: GigabitEthernet0/0/0/0 + multicast_client: 224.0.0.8 + multicast_destination: 224.0.0.8 + broadcast_client: true + ipv4: + dscp: af11 + ipv6: + precedence: routine + log_internal_sync: true + master: 1 + max_associations: 10 + passive: true + peers: + - iburst: true + peer: 192.0.2.1 + vrf: siteC + servers: + - burst: true + server: 192.0.2.2 + vrf: siteD + source: GigabitEthernet0/0/0/0 + source_vrfs: + - name: GigabitEthernet0/0/0/0 + vrf: siteE + trusted_keys: + - key_id: 1 + update_calendar: true + register: result +# Module Execution Result: +# ------------------------ +# "rendered": [ +# "ntp peer vrf siteC 192.0.2.1 iburst ", +# "ntp server vrf siteD 192.0.2.2 burst ", +# "ntp trusted-key 1", +# "ntp interface GigabitEthernet0/0/0/0 broadcast client", +# "ntp interface GigabitEthernet0/0/0/0 multicast destination 224.0.0.8", +# "ntp interface GigabitEthernet0/0/0/0 multicast client 224.0.0.8", +# "ntp vrf siteE source GigabitEthernet0/0/0/0", +# "ntp access-group vrf siteA ipv4 serve ServeAcl2", +# "ntp access-group vrf siteA ipv4 peer PeerAcl3", +# "ntp access-group ipv4 peer PeerAcl1", +# "ntp access-group ipv4 serve ServeAcl1", +# "ntp access-group ipv4 serve-only ServeOnlyAcl1", +# "ntp access-group ipv4 query-only QueryOnlyAcl1", +# "ntp authenticate", +# "ntp log-internal-sync", +# "ntp broadcastdelay 1", +# "ntp drift aging time 0", +# "ntp drift file apphost", +# "ntp ipv4 dscp af11", +# "ntp ipv6 precedence routine", +# "ntp max-associations 10", +# "ntp master 1", +# "ntp passive", +# "ntp update-calendar", +# "ntp source GigabitEthernet0/0/0/0" +# ], +# Using state: parsed +# File: parsed.cfg +# ---------------- +# ntp +# max-associations 10 +# interface GigabitEthernet0/0/0/0 +# broadcast client +# multicast client 224.0.0.8 +# multicast destination 224.0.0.8 +# ! +# authenticate +# trusted-key 1 +# ipv4 dscp af11 +# ipv6 precedence routine +# peer vrf siteC 192.0.2.1 iburst +# server vrf siteD 192.0.2.2 burst +# drift file apphost +# drift aging time 0 +# master 1 +# access-group vrf siteA ipv4 peer PeerAcl3 +# access-group vrf siteA ipv4 serve ServeAcl2 +# access-group ipv4 peer PeerAcl1 +# access-group ipv4 serve ServeAcl1 +# access-group ipv4 serve-only ServeOnlyAcl1 +# access-group ipv4 query-only QueryOnlyAcl1 +# source vrf siteE GigabitEthernet0/0/0/0 +# source GigabitEthernet0/0/0/0 +# passive +# broadcastdelay 1 +# update-calendar +# log-internal-sync +# ! +# Parsed play: +# ------------ +- name: Parse the provided configuration with the existing running configuration + cisco.iosxr.iosxr_ntp_global: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed +# Module Execution Result: +# ------------------------ +# "parsed":{ +# "access_group": { +# "ipv4": { +# "peer": "PeerAcl1", +# "query_only": "QueryOnlyAcl1", +# "serve": "ServeAcl1", +# "serve_only": "ServeOnlyAcl1" +# }, +# "vrfs": [ +# { +# "ipv4": { +# "peer": "PeerAcl3", +# "serve": "ServeAcl2" +# }, +# "name": "siteA" +# } +# ] +# }, +# "authenticate": true, +# "broadcastdelay": 1, +# "drift": { +# "aging_time": 0, +# "file": "apphost" +# }, +# "interfaces": [ +# { +# "broadcast_client": true, +# "multicast_client": "224.0.0.8", +# "multicast_destination": "224.0.0.8", +# "name": "GigabitEthernet0/0/0/0" +# } +# ], +# "ipv4": { +# "dscp": "af11" +# }, +# "ipv6": { +# "precedence": "routine" +# }, +# "log_internal_sync": true, +# "master": 1, +# "max_associations": 10, +# "passive": true, +# "peers": [ +# { +# "iburst": true, +# "peer": "192.0.2.1", +# "vrf": "siteC" +# } +# ], +# "servers": [ +# { +# "burst": true, +# "server": "192.0.2.2", +# "vrf": "siteD" +# } +# ], +# "source": "GigabitEthernet0/0/0/0", +# "source_vrfs": [ +# { +# "name": "GigabitEthernet0/0/0/0", +# "vrf": "siteE" +# } +# ], +# "trusted_keys": [ +# { +# "key_id": 1 +# } +# ], +# "update_calendar": true +# } +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ntp_global.ntp_global import ( + Ntp_globalArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ntp_global.ntp_global import ( + Ntp_global, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ntp_globalArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Ntp_global(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospf_interfaces.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospf_interfaces.py new file mode 100644 index 00000000..02ec5acb --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospf_interfaces.py @@ -0,0 +1,1211 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_ospf_interfaces +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_ospf_interfaces +version_added: 1.2.0 +short_description: Resource module to configure OSPF interfaces. +description: + - This module manages OSPF(v2/v3) configuration of interfaces on devices running Cisco IOS-XR. +author: Rohit Thakur (@rohitthakur2590) +notes: + - This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html) +options: + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config router ospf'). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + config: + description: A list of OSPF configuration for interfaces. + type: list + elements: dict + suboptions: + name: + description: + - Name/Identifier of the interface. + type: str + required: True + type: + description: + - Type of the interface. + type: str + required: True + address_family: + description: + - OSPF settings on the interfaces in address-family context. + type: list + elements: dict + suboptions: + afi: + description: + - Address Family Identifier (AFI) for OSPF settings on the interfaces. + type: str + choices: ['ipv4', 'ipv6'] + required: True + processes: + description: + - Interfaces configuration for an OSPF process. + type: list + elements: dict + suboptions: + process_id: + description: + - OSPF process tag. + type: str + required: True + area: + description: Specify the area-id + type: dict + suboptions: + area_id: + description: + - OSPF interfaces area ID as a decimal value. Please + refer vendor documentation of Valid values. + - OSPF interfaces area ID in IP address format(e.g. + A.B.C.D) + type: str + apply_group_option: + description: Specify configuration from a group + type: dict + suboptions: + group_name: + description: Specify the name of the group + type: str + operation: + description: Specify the group config operation + type: str + choices: [add, remove, append] + authentication: + description: Enable authentication + type: dict + suboptions: + message_digest: + description: Use message-digest authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + null_auth: + description: Use no authentication + type: bool + authentication_key: + description: Specify authentication password (key) + type: dict + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will follow + type: str + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: str + bfd: + description: Configure BFD parameters + type: dict + suboptions: + fast_detect: + description: Configure fast detection + type: dict + suboptions: + set: + description: Enable fast detection only + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + minimum_interval: + description: Hello interval in milli-seconds + type: int + multiplier: + description: Detect multiplier + type: int + cost: + description: Specify Interface cost + type: int + cost_fallback: + description: Specify Cost when cumulative bandwidth goes below the theshold + type: dict + suboptions: + cost: + description: Specify cost w.r.t cummulative bandwidth + type: int + threshold: + description: Specify threshold bandwidth when cost-fallback is applied + type: int + database_filter: + description: Filter OSPF LSAs during synchronization and flooding + type: dict + suboptions: + all_outgoing_lsa: + description: Filter all outgoing LSA + type: bool + dead_interval: + description: Specify interval after which a neighbor is declared dead + type: int + demand_circuit: + description: Enable/Disable demand circuits + type: bool + fast_reroute: + description: Specify IP Fast Reroute + type: dict + suboptions: + disabled: + description: Disable IP fast reroute + type: bool + per_link: + description: Specify per-prefix computation + type: dict + suboptions: + information_type: + description: Specify per-link LFA exclusion or FRR LFA candidate information + type: str + choices: ["exclude", "lfa_candidate"] + use_candidate_only: + description: Enable/Disable backup selection from candidate-list only + type: bool + interface: + description: Specify Per-link LFA exclusion information + type: dict + suboptions: + bvi: + description: Specify Bridge-Group Virtual Interface + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + bundle_ether: + description: Specify Aggregated Ethernet interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + pos_int: + description: Specify Aggregated pos interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + fast_ethernet: + description: Specify FastEthernet/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + fiftygige: + description: Specify FiftyGigE/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + fortygige: + description: Specify FortyGigE/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + fourhundredgige: + description: Specify FourHundredGigE/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + gigabitethernet: + description: Specify GigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + hundredgige: + description: Specify HundredGigE/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + mgmteth: + description: Specify MgmtEth/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + multilink: + description: Specify Multilink network interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + pw_ether: + description: Specify PWHE Ethernet Interface + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + pw_iw: + description: Specify PWHE VC11 IP Interworking Interface + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + srp: + description: Specify SRP interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + serial: + description: Specify Serial network interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + tengige: + description: Specify TenGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + twentyfivegige: + description: Specify TwentyFiveGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + twohundredgige: + description: Specify TwoHundredGigE/IEEE 802.3 interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + nve: + description: Specify Network Virtualization Endpoint Interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + tunnel_ip: + description: Specify GRE/IPinIP Tunnel Interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + tunnel_ipsec: + description: Specify IPSec Tunnel interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + tunnel_mte: + description: Specify MPLS Traffic Engineering P2MP Tunnel interface(s) + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: int + tunnel_mpls: + description: MPLS Transport Protocol Tunnel interface + type: list + elements: dict + suboptions: + name: + description: Specify the interface id + type: str + flood_reduction: + description: Enable/Disable flood reduction + type: bool + hello_interval: + description: Specify Time between HELLO packets + type: int + link_down_fast_detect: + description: Configure interface down parameters + type: bool + message_digest_key: + description: Message digest authentication password (key) + type: dict + suboptions: + id: + description: Key ID + type: int + required: true + md5: + description: Use MD5 Algorithm + type: dict + required: true + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will follow + type: bool + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: bool + mpls_ldp_sync: + description: Enable/Disable MPLS LDP Sync + type: bool + mtu_ignore: + description: Enable/Disable ignoring of MTU in DBD packets + type: bool + network: + description: Specify Network type + type: str + choices: ["broadcast", "non-broadcast", "point-to-multipoint", "point-to-point"] + neighbors: + description: Specify a neighbor routers + type: list + elements: dict + suboptions: + neighbor_id: + description: Specify Neighbor address (name) + type: str + cost: + description: Specify OSPF cost for point-to-multipoint neighbor + type: int + db_filter_all_out: + description: Specify Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor + type: bool + poll_interval: + description: Specify OSPF dead-router polling interval + type: int + priority: + description: Specify OSPF priority of non-broadcast neighbor + type: int + packet_size: + description: Customize size of OSPF packets upto MTU + type: int + passive: + description: Enable/Disable passive + type: bool + prefix_suppression: + description: Suppress advertisement of the prefixes + type: bool + priority: + description: Specify Router priority + type: int + retransmit_interval: + description: Specify time between retransmitting lost link state advertisements + type: int + security_ttl: + description: Enable security + type: dict + suboptions: + set: + description: Enable ttl security + type: bool + hops: + description: Maximum number of IP hops allowed <1-254> + type: int + transmit_delay: + description: Specify estimated time needed to send link-state update packet + type: int + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# % No such configuration item(s) +# + +- name: Merge provided OSPF interfaces configuration with the existing configuration + cisco.iosxr.iosxr_ospf_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + type: gigabitethernet + address_family: + - afi: ipv4 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.3 + cost: 20 + authentication: + message_digest: + keychain: cisco + - afi: ipv6 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.2 + cost: 30 + state: merged + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": [] +# +# "commands": [ +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 cost 20", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest keychain cisco", +# "router ospfv3 LAB3 area 0.0.0.2 interface GigabitEthernet 0/0/0/0 cost 30" +# ] +# +# "after": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "cisco" +# } +# }, +# "cost": 20, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.2" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +# +# ------------ +# After state +# ------------ +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:00:57.217 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/0 +# cost 20 +# authentication message-digest keychain cisco +# ! +# ! +# ! +# router ospf ipv4 +# ! + +# Using replaced +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:00:57.217 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/0 +# cost 20 +# authentication message-digest keychain cisco +# ! +# ! +# ! +# router ospf ipv4 +# ! + +- name: Replace OSPF interfaces configuration + cisco.iosxr.iosxr_ospf_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + type: gigabitethernet + address_family: + - afi: ipv4 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.3 + cost: 30 + authentication: + message_digest: + keychain: ciscoiosxr + - afi: ipv6 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.2 + cost: 30 + state: replaced + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "cisco" +# } +# }, +# "cost": 20, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.2" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +# "commands": [ +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 cost 30", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest keychain ciscoiosxr" +# ] +# +# "after": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "ciscoiosxr" +# } +# }, +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.2" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +# +# ----------- +# After state +# ----------- +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:10:39.827 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/0 +# cost 30 +# authentication message-digest keychain ciscoiosxr +# ! +# ! +# ! +# router ospf ipv4 +# ! + +- name: Override existing OSPF interfaces configuration + cisco.iosxr.iosxr_ospf_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + type: gigabitethernet + address_family: + - afi: ipv4 + processes: + - process_id: "LAB1" + area: + area_id: 0.0.0.3 + cost: 10 + authentication: + message_digest: + keychain: iosxr + state: overridden + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "ciscoiosxr" +# } +# }, +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.2" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +# "commands": [ +# "no router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0", +# "no router ospfv3 LAB3 area 0.0.0.2 interface GigabitEthernet 0/0/0/0", +# "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 cost 10", +# "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest", +# "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest keychain iosxr" +# ] +# +# "after": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "iosxr" +# } +# }, +# "cost": 10, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB1" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/1", +# "type": "gigabitethernet" +# } +# ] +# +# +# ----------- +# After state +# ----------- +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:28:15.025 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/1 +# cost 10 +# authentication message-digest keychain iosxr +# ! +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# ! +# ! +# router ospf ipv4 +# ! + +# Using deleted +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:28:15.025 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/1 +# cost 10 +# authentication message-digest keychain iosxr +# ! +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# ! +# ! +# router ospf ipv4 +# ! + +- name: Deleted existing OSPF interfaces from the device + cisco.iosxr.iosxr_ospf_interfaces: + config: + - name: GigabitEthernet0/0/0/1 + type: gigabitethernet + state: deleted + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "iosxr" +# } +# }, +# "cost": 10, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB1" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/1", +# "type": "gigabitethernet" +# } +# ], +# +# "commands": [ +# "no router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1" +# ] +# +# "after": [] +# +# +# ----------- +# After state +# ----------- +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:34:38.319 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# ! +# ! +# router ospf ipv4 +# ! + +# Using parsed +# parsed.cfg +# ------------ +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/0 +# cost 20 +# authentication message-digest keychain cisco +# ! +# ! +# ! +# router ospf ipv4 +# ! +- name: Parsed the device configuration to get output commands + cisco.iosxr.iosxr_ospf_interfaces: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "cisco" +# } +# }, +# "cost": 20, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +# Using rendered +# +# +- name: Render the commands for provided configuration + cisco.iosxr.iosxr_ospf_interfaces: + config: + - name: GigabitEthernet0/0/0/0 + type: gigabitethernet + address_family: + - afi: ipv4 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.3 + cost: 20 + authentication: + message_digest: + keychain: cisco + - afi: ipv6 + processes: + - process_id: "LAB3" + area: + area_id: 0.0.0.2 + cost: 30 + state: rendered + +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 cost 20", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest", +# "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest keychain cisco", +# "router ospfv3 LAB3 area 0.0.0.2 interface GigabitEthernet 0/0/0/0 cost 30" +# ] + + +# Using gathered +# +# Before state: +# ------------- +# +# RP/0/0/CPU0:an-iosxr-02#show running-config router ospf +# Thu Oct 23 06:50:38.743 UTC +# router ospf LAB +# area 0.0.0.0 +# ! +# area 0.0.0.9 +# ! +# ! +# router ospf LAB1 +# area 0.0.0.1 +# ! +# area 0.0.0.3 +# ! +# ! +# router ospf LAB3 +# area 0.0.0.3 +# interface GigabitEthernet0/0/0/0 +# cost 20 +# authentication message-digest keychain cisco +# ! +# ! +# ! +# router ospf ipv4 +# ! + + +- name: Gather ospf_interfaces routes configuration + cisco.iosxr.iosxr_ospf_interfaces: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": [ +# { +# "address_family": [ +# { +# "afi": "ipv4", +# "authentication": { +# "message_digest": { +# "keychain": "cisco" +# } +# }, +# "cost": 20, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.3" +# }, +# "process_id": "LAB3" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "cost": 30, +# "processes": [ +# { +# "area": { +# "area_id": "0.0.0.2" +# }, +# "process_id": "LAB3" +# } +# ] +# } +# ], +# "name": "GigabitEthernet0/0/0/0", +# "type": "gigabitethernet" +# } +# ] +# +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospf_interfaces.ospf_interfaces import ( + Ospf_interfacesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ospf_interfaces.ospf_interfaces import ( + Ospf_interfaces, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ospf_interfacesArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Ospf_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv2.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv2.py new file mode 100644 index 00000000..4b41338d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv2.py @@ -0,0 +1,2545 @@ +#!/usr/bin/python +# +# 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/>. +# + +""" +The module file for iosxr_ospfv2 +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_ospfv2 +short_description: Resource module to configure OSPFv2. +description: This module manages global OSPFv2 configuration on devices running Cisco + IOS-XR +version_added: 1.0.0 +author: +- Rohit Thakur (@rohitthakur2590) +notes: +- This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html) +options: + config: + description: A list of OSPFv2 process configuration + type: dict + suboptions: + processes: + description: A list of OSPFv2 instances configuration + type: list + elements: dict + suboptions: + address_family_unicast: + description: Enable unicast topology for ipv4 address family + type: bool + adjacency_stagger: + description: Stagger OSPFv2 adjacency bring up + type: dict + suboptions: + min_adjacency: + description: Initial number of neighbors to bring up per area (default + 2) + type: int + max_adjacency: + description: Maximum simultaneous neighbors to bring up + type: int + disable: + description: Disable stagger OSPFv2 adjacency + type: bool + authentication: + description: Enable authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + message_digest: + description: Use message-digest authentication + type: dict + suboptions: + set: + description: Specify message-digest selection + type: bool + keychain: + description: Specify keychain name + type: str + no_auth: + description: Use no authentication + type: bool + apply_weight: + description: Enable weights configured under interfaces for load sharing + type: dict + suboptions: + bandwidth: + description: Reference bandwidth to use for calculation (Mbits/sec) + type: int + default_weight: + description: Specify default weight value to use when it is not configured + under interface + type: int + areas: + description: Configure OSPFv2 areas' properties + type: list + elements: dict + suboptions: + area_id: + description: Area ID as IP address or integer + type: str + required: true + authentication: + description: Enable authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + message_digest: + description: Use message-digest authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + no_auth: + description: Use no authentication + type: bool + authentication_key: + description: Used to mention authentication password (key) + type: dict + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will follow + type: str + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: str + default_cost: + description: Set the summary default-cost of a NSSA/stub area. Stub's + advertised external route metric + type: int + cost: + description: Interface cost + type: int + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + hello_interval: + description: Time between HELLO packets + type: int + transmit_delay: + description: Estimated time needed to send link-state update packet + type: int + mpls: + description: Configure MPLS routing protocol parameters + type: dict + suboptions: + traffic_eng: + description: Configure an ospf area to run MPLS Traffic Engineering + type: bool + ldp: + description: Configure LDP parameters + type: dict + suboptions: + auto_config: + description: Enable LDP IGP interface auto-configuration + type: bool + sync: + description: Enable LDP IGP synchronization + type: bool + sync_igp_shortcuts: + description: LDP sync for igp-shortcut tunnels + type: bool + mtu_ignore: + description: Enable/Disable ignoring of MTU in DBD packets + type: str + choices: + - enable + - disable + bfd: + description: Configure BFD parameters + type: dict + suboptions: + fast_detect: + description: Configure fast detection + type: dict + suboptions: + set: + description: Enable fast detection only + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + minimum_interval: + description: Hello interval in milli-seconds + type: int + multiplier: + description: Detect multiplier + type: int + nssa: + description: + - NSSA settings for the area + type: dict + suboptions: + set: + description: Configure area as NSSA + type: bool + default_information_originate: + description: Originate default Type 7 LSA + type: dict + suboptions: + metric: + description: OSPFv2 default metric + type: int + metric_type: + description: Metric type for default routes + type: int + no_redistribution: + description: Do not send redistributed LSAs into NSSA area + type: bool + no_summary: + description: Do not send summary LSAs into NSSA area + type: bool + translate: + description: Translate LSA + type: dict + suboptions: + type7: + description: + - Translate from Type 7 to Type 5 + type: dict + suboptions: + always: + description: + - Always translate LSAs + type: bool + ranges: + description: Summarize routes matching address/mask (border routers + only) + type: list + elements: dict + suboptions: + address: + description: IP in Prefix format (x.x.x.x/len) + type: str + required: true + advertise: + description: Advertise this range (default) + type: bool + not_advertise: + description: DoNotAdvertise this range + type: bool + route_policy: + description: Specify the route-policy to filter type 3 LSAs (list + can have one inbound and/or one outbound policy only) + type: list + elements: dict + suboptions: + parameters: + description: Specify parameter values for the policy + type: list + elements: str + direction: + description: Specify inbound or outbound + type: str + choices: + - in + - out + stub: + description: + - Settings for configuring the area as a stub + type: dict + suboptions: + set: + description: + - Configure the area as a stub + type: bool + no_summary: + description: + - Do not send summary LSA into stub area + type: bool + virtual_link: + description: Define a virtual link + type: list + elements: dict + suboptions: + id: + description: Router-ID of virtual link neighbor (A.B.C.D) + type: str + required: true + authentication: + description: Enable authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + message_digest: + description: Use message-digest authentication + type: dict + suboptions: + keychain: + description: Specify keychain name + type: str + no_auth: + description: Use no authentication + type: bool + authentication_key: + description: Used to mention authentication password (key) + type: dict + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will + follow + type: str + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: str + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + hello_interval: + description: Time between HELLO packets + type: int + retransmit_interval: + description: Delay between LSA retransmissions + type: int + transmit_delay: + description: Link state transmit delay + type: int + message_digest_key: + description: Message digest authentication password (key) + type: dict + suboptions: + id: + description: Key ID (1-255) + type: int + required: true + md5: + description: Use MD5 Algorithm + type: dict + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will + follow + type: bool + encrypted: + description: Specifies an ENCRYPTED password (key) will + follow + type: bool + + authentication_key: + description: Used to mention authentication password (key) + type: dict + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will follow + type: bool + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: bool + auto_cost: + description: Calculate OSPFv2 interface cost according to bandwidth + type: dict + suboptions: + reference_bandwidth: + description: Specify reference bandwidth in megabits per sec + type: int + disable: + description: Assign OSPFv2 cost based on interface type + type: bool + bfd: + description: Configure BFD parameters + type: dict + suboptions: + fast_detect: + description: Configure fast detection + type: dict + suboptions: + set: + description: Enable fast detection only + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + minimum_interval: + description: Hello interval in milli-seconds + type: int + multiplier: + description: Detect multiplier + type: int + capability: + description: Enable specific OSPFv2 feature + type: dict + suboptions: + type7: + description: NSSA capability + type: str + opaque: + description: Configure opaque LSA + type: dict + suboptions: + disable: + description: Disable Opaque LSA capability + type: bool + set: + description: Enable opaque LSA + type: bool + cost: + description: Interface cost (1-65535) + type: int + database_filter: + description: Filter OSPFv2 LSA during synchronization and flooding (all + outgoing LSA). Enable/Disable filtering + type: str + choices: [enable, disable] + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + default_information_originate: + description: Distribute default route + type: dict + suboptions: + always: + description: Always advertise default route + type: bool + metric: + description: OSPFv2 default metric + type: int + metric_type: + description: OSPFv2 metric type for default routes + type: int + route_policy: + description: Apply route-policy to default-information origination + type: str + set: + description: Enable distribution of default route + type: bool + default_metric: + description: Set metric of redistributed routes + type: int + demand_circuit: + description: Enable/Disable OSPFv2 demand circuit + type: str + choices: [enable, disable] + distance: + description: Define an administrative distance + type: dict + suboptions: + admin_distance: + description: Administrative distance + type: list + elements: dict + suboptions: + value: + description: Distance value + type: int + source: + description: Source IP address + type: str + wildcard: + description: IP wild card bits (A.B.C.D) + type: str + access_list: + description: Access list name + type: str + ospf_distance: + description: OSPFv2 administrative distance + type: dict + suboptions: + external: + description: Distance for external routes + type: int + inter_area: + description: Distance for inter-area routes + type: int + intra_area: + description: Distance for intra-area routes + type: int + distribute_link_state: + description: Enable Distribution of LSAs to external services + type: dict + suboptions: + instance_id: + description: Set distribution process instance identifier + type: int + throttle: + description: Throttle time between successive LSA updates + type: int + distribute_bgp_ls: + description: Enable Distribution of LSAs to external services + type: dict + suboptions: + instance_id: + description: Set distribution process instance identifier + type: int + throttle: + description: Throttle time between successive LSA updates + type: int + distribute_list: + description: Filter networks in routing updates (list can have one inbound + and/or one outbound policy only) + type: list + elements: dict + suboptions: + access_list: + description: Inbound/outbound access-list + type: str + direction: + description: Filter incoming/outgoing routing updates + type: str + choices: + - in + - out + outgoing_params: + description: Specify additional parameters for outgoing updates only + type: dict + suboptions: + route_type: + description: Type of routes + type: str + choices: + - bgp + - connected + - dagr + - ospf + - static + id: + description: + - For BGP, specify AS number. 2-byte AS number (or) 4-byte AS + number in asdot (X.Y) format (or) 4-byte AS number in asplain + format + - For OSPF, specify OSPFv2 instance name + type: str + route_policy: + description: Route Policy to filter OSPFv2 prefixes (for incoming + updates only) + type: str + external_out: + description: Enable/Disable advertisement of intra-area prefixes as external + type: str + choices: + - enable + - disable + flood_reduction: + description: Enable/Disable OSPFv2 Flood Reduction + type: str + choices: + - enable + - disable + hello_interval: + description: Time between HELLO packets (<1-65535> seconds) + type: int + ignore_lsa_mospf: + description: Do not complain upon receiving MOSPFv2 Type 6 LSA + type: bool + link_down_fast_detect: + description: Enable fast or early detection of link-down events + type: bool + log_adjacency_changes: + description: Log adjacency state changes + type: dict + suboptions: + set: + description: Set log adjacency + type: bool + disable: + description: Disable log adjacency changes + type: bool + detail: + description: Log all state changes + type: bool + loopback_stub_network: + description: Advertise loopback as a stub network + type: str + choices: + - enable + - disable + max_lsa: + description: + - Feature to limit the number of non-self-originated LSAs + type: dict + suboptions: + threshold: + description: + - Threshold value (%) at which to generate a warning message + type: int + ignore_count: + description: + - Set count on how many times adjacencies can be suppressed + type: int + ignore_time: + description: + - Set number of minutes during which all adjacencies are suppressed + type: int + reset_time: + description: + - Set number of minutes after which ignore-count is reset to zero + type: int + warning_only: + description: + - Log a warning message when limit is exceeded + type: bool + max_metric: + description: Set maximum metric + type: dict + suboptions: + router_lsa: + description: Maximum metric in self-originated router-LSAs + type: dict + suboptions: + set: + description: Set router-lsa attribute + type: bool + external_lsa: + description: External LSA configuration + type: dict + suboptions: + set: + description: Set external-lsa attribute + type: bool + max_metric_value: + description: Set max metric value for external LSAs + type: int + include_stub: + description: + - Advertise Max metric for Stub links as well + type: bool + on_startup: + description: + - Effective only at startup + type: dict + suboptions: + set: + description: + - Set on-startup attribute + type: bool + wait_period: + description: + - Wait period in seconds after startup + type: int + wait_for_bgp_asn: + description: + - ASN of BGP to wait for + type: int + summary_lsa: + description: + - Summary LSAs configuration + type: dict + suboptions: + set: + description: + - Set summary-lsa attribute + type: bool + max_metric_value: + description: + - Max metric value for summary LSAs + type: int + message_digest_key: + description: Message digest authentication password (key) + type: dict + suboptions: + id: + description: Key ID + type: int + required: true + md5: + description: Use MD5 Algorithm + type: dict + required: true + suboptions: + password: + description: The OSPFv2 password (key) + type: str + clear: + description: Specifies an UNENCRYPTED password (key) will follow + type: bool + encrypted: + description: Specifies an ENCRYPTED password (key) will follow + type: bool + microloop_avoidance: + description: Avoid microloops + type: dict + suboptions: + protected: + description: Avoid microloops for protected prefixes only) + type: bool + rib_update_delay: + description: Delay to introduce between SPF and RIB updates + type: int + segment_routing: + description: Enable segment routing microloop avoidance + type: bool + monitor_convergence: + description: Enables OSPFv2 route convergence monitoring + type: dict + suboptions: + prefix_list: + description: Enables Individual Prefix Monitoring + type: str + track_external_routes: + description: Enables Tracking External(Type-5/7) Prefix monitoring + type: bool + track_ip_frr: + description: Enables Tracking IP-Frr Convergence + type: bool + track_summary_routes: + description: Enables Tracking Summary(Inter-Area) Prefix monitoring + type: bool + mpls: + description: Configure MPLS routing protocol parameters + type: dict + suboptions: + traffic_eng: + description: Routing protocol commands for MPLS Traffic Engineering + type: dict + suboptions: + autoroute_exclude: + description: Exclude IP address destinations from using TE tunnels + type: dict + suboptions: + route_policy: + description: Policy name + type: str + parameters: + description: Specify parameter values for the policy + type: list + elements: str + igp_intact: + description: Retain one or more IPv4 nexthops with tunnel nexthops + type: bool + ldp_sync_update: + description: Enable LDP sync induced metric propagation + type: bool + multicast_intact: + description: Publish multicast-intact paths to RIB + type: bool + router_id: + description: Traffic Engineering stable IP address for system + type: str + ldp: + description: Configure LDP parameters + type: dict + suboptions: + auto_config: + description: Enable LDP IGP interface auto-configuration + type: bool + sync: + description: Enable LDP IGP synchronization + type: bool + sync_igp_shortcuts: + description: LDP sync for igp-shortcut tunnels + type: bool + mtu_ignore: + description: Enable/Disable ignoring of MTU in DBD packets + type: str + choices: + - enable + - disable + network: + description: Network type + type: dict + suboptions: + broadcast: + description: Specify OSPFv2 broadcast multi-access network + type: bool + non_broadcast: + description: Specify OSPFv2 NBMA network + type: bool + point_to_multipoint: + description: Specify OSPFv2 point-to-multipoint network + type: bool + point_to_point: + description: Specify OSPFv2 point-to-point network + type: bool + nsf: + description: Non-stop forwarding + type: dict + suboptions: + cisco: + description: Cisco Non-stop forwarding + type: dict + suboptions: + enforce_global: + description: Cancel NSF restart when non-NSF-aware neighbors detected + for the whole OSPFv2 process + type: bool + set: + description: Enable Cisco NSF + type: bool + flush_delay_time: + description: Maximum time allowed for external route learning + type: int + ietf: + description: IETF graceful restart + type: dict + suboptions: + helper_disable: + description: Disable router's helper support level + type: bool + set: + description: Only enable ietf option + type: bool + interval: + description: Minimum interval between NSF restarts (<90-3600> seconds) + type: int + lifetime: + description: Maximum route lifetime following restart (<90-1800> seconds) + type: int + nsr: + description: Enable NSR for all VRFs in this process. 'False' option to + disable NSR for all VRFs in this process + type: bool + packet_size: + description: Size of OSPFv2 packets to use. min=576 max=MTU bytes + type: int + passive: + description: Enable/Disable passive + type: str + choices: + - enable + - disable + prefix_suppression: + description: Suppress advertisement of the prefixes + type: dict + suboptions: + set: + description: Set the suppression option + type: bool + secondary_address: + description: Enable/Disable secondary address suppression + type: bool + priority: + description: Router priority + type: int + process_id: + description: The OSPFv2 Process ID + type: str + required: true + protocol_shutdown: + description: Protocol specific configuration + type: dict + suboptions: + host_mode: + description: Only traffic destined for this box allowed(cisco-support) + type: bool + on_reload: + description: Shutdown post reload only + type: bool + set: + description: Shutdown the OSPFv2 Protocol + type: bool + limit: + description: High watermark for incoming priority events + type: dict + suboptions: + high: + description: Hello events are dropped when incoming event queue + exceeds this value + type: int + low: + description: DBD/LS Update/Req packets are dropped when incoming + event queue exceeds this value + type: int + medium: + description: LSA ACKs are dropped when incoming event queue exceeds + this value + type: int + redistribute: + description: Redistribute information from another routing Protocol + type: dict + suboptions: + route_type: + description: Route type to redistribute + type: str + choices: [application, bgp, connected, dagr, eigrp, isis, mobile, + ospf, rip, static, subscriber] + id: + description: OnePK application name for application routes (or) AS + number for bgp and eigrp (or) instance name for isis and ospf + type: str + level: + description: ISIS levels + choices: [1, 2, 12] + type: int + lsa_type_summary: + description: LSA type 3 for redistributed routes + type: bool + match: + description: Redistribution of routes. For OSPFv2 - external/internal/nssa-external + 1/2. For EIGRP - external/internal + type: str + metric: + description: Metric for redistributed routes + type: int + metric_type: + description: OSPFv2 exterior metric type for redistributed routes + type: int + choices: [1, 2] + route_policy: + description: Apply route-policy to redistribution + type: dict + suboptions: + name: + description: Name of the policy + type: str + parameters: + description: Specify parameter values for the policy + type: list + elements: str + nssa_only: + description: Redistribute to NSSA areas only + type: bool + preserve_med: + description: Preserve med of BGP routes + type: bool + tag: + description: Set tag for routes redistributed into OSPFv2 + type: int + retransmit_interval: + description: Delay between LSA retransmissions + type: int + router_id: + description: OSPFv2 router-id in IPv4 address format (A.B.C.D) + type: str + security_ttl: + description: Enable security + type: dict + suboptions: + set: + description: Enable ttl security + type: bool + hops: + description: Maximum number of IP hops allowed <1-254> + type: int + summary_in: + description: Enable/Disable advertisement of external prefixes as inter-area + type: str + choices: [enable, disable] + summary_prefix: + description: Configure IP address summaries + type: list + elements: dict + suboptions: + prefix: + description: IP summary address/mask (A.B.C.D/prefix) + type: str + required: true + not_advertise: + description: Suppress routes that match the specified prefix/mask + pair + type: bool + tag: + description: Set tag + type: int + timers: + description: Configure timer related constants + type: dict + suboptions: + graceful_shutdown: + description: Timers for graceful shutdown(cisco-support) + type: dict + suboptions: + initial_delay: + description: Delay before starting graceful shutdown + type: int + retain_routes: + description: Time to keep routes active after graceful shutdown + type: int + lsa: + description: OSPFv2 global LSA timers + type: dict + suboptions: + group_pacing: + description: OSPFv2 LSA group pacing timer. Interval between group + of LSA being refreshed or maxaged + type: int + min_arrival: + description: OSPFv2 MinLSArrival timer. The minimum interval in + millisec between accepting the same LSA + type: int + refresh: + description: OSPFv2 LSA refresh interval. How often self-originated + LSAs should be refreshed, in seconds + type: int + throttle: + description: OSPFv2 throttle timers + type: dict + suboptions: + lsa_all: + description: LSA throttle timers for all types of OSPFv2 LSAs + type: dict + suboptions: + initial_delay: + description: Delay to generate first occurance of LSA in milliseconds + type: int + min_delay: + description: Minimum delay between originating the same LSA + in milliseconds + type: int + max_delay: + description: Maximum delay between originating the same LSA + in milliseconds + type: int + spf: + description: OSPFv2 SPF throttle timers + type: dict + suboptions: + change_delay: + description: Delay between receiving a change to SPF calculation + in milliseconds + type: int + second_delay: + description: Delay between first and second SPF calculation + in milliseconds + type: int + max_wait: + description: Maximum wait time in milliseconds for SPF calculations + type: int + fast_reroute: + description: Fast-reroute throttle timer. Delay between end of + SPF and start of the fast-reroute computation in milliseconds + type: int + pacing_flood: + description: OSPFv2 flood pacing timer. Interval in msec to pace flooding + on all interfaces + type: int + transmit_delay: + description: Estimated time needed to send link-state update packet + type: int + weight: + description: Interface weight + type: int + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config router ospf). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - deleted + - parsed + - gathered + - rendered + - overridden + default: merged + +""" + +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 15:54:44.569 UTC +# % No such configuration item(s) +# + +- name: Merge provided OSPFv2 configuration with the existing configuration + cisco.iosxr.iosxr_ospfv2: + config: + processes: + - process_id: '27' + areas: + - area_id: '10' + hello_interval: 2 + authentication: + keychain: ansi11393 + - process_id: '26' + adjacency_stagger: + max_adjacency: 20 + min_adjacency: 10 + - process_id: '10' + authentication: + keychain: ansible_test1102 + areas: + - area_id: '11' + default_cost: 5 + cost: 11 + - area_id: 22 + default_cost: 6 + - process_id: '30' + areas: + - area_id: 11 + default_cost: 5 + - area_id: 22 + default_cost: 6 + + cost: 2 + default_metric: 10 + transmit_delay: 2 + hello_interval: 1 + dead_interval: 2 + retransmit_interval: 2 + weight: 2 + packet_size: 577 + priority: 1 + router_id: 2.2.2.2 + demand_circuit: enable + passive: disable + summary_in: enable + flood_reduction: disable + mtu_ignore: enable + external_out: disable + state: merged + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": {} +# +# "commands": [ +# "router ospf 30", +# "cost 2", +# "weight 2", +# "passive disable", +# "priority 1", +# "flood-reduction disable", +# "default-metric 10", +# "router-id 2.2.2.2", +# "demand-circuit enable", +# "packet-size 577", +# "transmit-delay 2", +# "summary-in enable", +# "external-out disable", +# "dead-interval 2", +# "hello-interval 1", +# "retransmit-interval 2", +# "mtu-ignore enable", +# "area 11 default-cost 5", +# "area 22 default-cost 6", +# "router ospf 26", +# "adjacency stagger 10 20", +# "authentication message-digest keychain ansible1101pass", +# "router ospf 27", +# "area 10 authentication keychain ansi11393", +# "area 10 hello-interval 2", +# "router ospf 10", +# "authentication keychain ansible_test1102", +# "area 11 default-cost 5", +# "area 11 cost 11", +# "area 22 default-cost 6" +# ] +# +# "after": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } +# +# +# ------------ +# After state +# ------------ +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# + + +# Using replaced +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# + +- name: Replace OSPFv2 routes configurations from the device + cisco.iosxr.iosxr_ospfv2: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + - area_id: 20 + cost: 2 + default_cost: 2 + authentication: + keychain: ansi11393 + - process_id: 26 + adjacency_stagger: + min_adjacency: 10 + max_adjacency: 20 + state: replaced + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } +# +# "commands": [ +# "router ospf 27", +# "no area 10 authentication keychain ansi11393", +# "area 20 authentication keychain ansi11393", +# "area 20 default-cost 2", +# "area 20 cost 2" +# ] +# +# "after": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton(config)#do show running-config router ospf +# Thu Jun 11 16:40:31.038 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# cost 2 +# authentication keychain ansi11393 +# default-cost 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# + + +# Using overridden +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# + +- name: Override existing OSPFv2 configurations from the device + cisco.iosxr.iosxr_ospfv2: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + authentication: + keychain: ansi11393 + - area_id: 20 + cost: 2 + default_cost: 2 + authentication: + keychain: ansi11393 + - process_id: 26 + adjacency_stagger: + min_adjacency: 10 + max_adjacency: 20 + state: overridden + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } +# +# "commands": [ +# "router ospf 10", +# "no authentication keychain ansible_test1102", +# "no area 11 default-cost 5", +# "no area 11 cost 11", +# "no area 22 default-cost 6", +# "router ospf 30", +# "no cost 2", +# "no weight 2", +# "no passive disable", +# "no priority 1", +# "no flood-reduction disable", +# "no default-metric 10", +# "no router-id 2.2.2.2", +# "no demand-circuit enable", +# "no packet-size 577", +# "no transmit-delay 2", +# "no summary-in enable", +# "no external-out disable", +# "no dead-interval 2", +# "no hello-interval 1", +# "no retransmit-interval 2", +# "no mtu-ignore enable", +# "no area 11 default-cost 5", +# "no area 22 default-cost 6", +# "router ospf 27", +# "area 20 authentication keychain ansi11393", +# "area 20 default-cost 2", +# "area 20 cost 2" +# ] +# +# "after": { +# "processes": [ +# { +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "process_id": "30" +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:50:36.332 UTC +# router ospf 10 +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# area 20 +# cost 2 +# authentication keychain ansi11393 +# default-cost 2 +# ! +# ! +# router ospf 30 +# ! +# + + +# Using deleted +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# + +- name: Deleted existing OSPFv2 configurations from the device + cisco.iosxr.iosxr_ospfv2: + config: + processes: + - process_id: '10' + - process_id: '26' + - process_id: '27' + - process_id: '30' + state: deleted + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# }, +# +# "commands": [ +# "router ospf 10", +# "no authentication keychain ansible_test1102", +# "no area 11 default-cost 5", +# "no area 11 cost 11", +# "no area 22 default-cost 6", +# "router ospf 26", +# "no adjacency stagger 10 20", +# "no authentication message-digest keychain ansible1101pass", +# "router ospf 27", +# "no area 10 authentication keychain ansi11393", +# "no area 10 hello-interval 2", +# "router ospf 30", +# "no cost 2", +# "no weight 2", +# "no passive disable", +# "no priority 1", +# "no flood-reduction disable", +# "no default-metric 10", +# "no router-id 2.2.2.2", +# "no demand-circuit enable", +# "no packet-size 577", +# "no transmit-delay 2", +# "no summary-in enable", +# "no external-out disable", +# "no dead-interval 2", +# "no hello-interval 1", +# "no retransmit-interval 2", +# "no mtu-ignore enable", +# "no area 11 default-cost 5", +# "no area 22 default-cost 6" +# ] +# +# "after": { +# "processes": [ +# { +# "process_id": "10" +# }, +# { +# "process_id": "26" +# }, +# { +# "process_id": "27" +# }, +# { +# "process_id": "30" +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton(config)#show running-config router ospf +# Thu Jun 11 17:07:34.218 UTC +# router ospf 10 +# ! +# router ospf 26 +# ! +# router ospf 27 +# ! +# router ospf 30 +# ! + + +# Using parsed +# parsed.cfg +# ------------ +# Thu Jun 11 17:28:51.918 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +- name: Parsed the device configuration to get output commands + cisco.iosxr.iosxr_ospfv2: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } + + + +# Using rendered +# +# +- name: Render the commands for provided configuration + cisco.iosxr.iosxr_ospfv2: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + authentication: + keychain: ansi11393 + - process_id: 26 + adjacency_stagger: + min_adjacency: 10 + max_adjacency: 20 + - process_id: 10 + authentication: + keychain: ansible_test1102 + areas: + - area_id: 11 + default_cost: 5 + cost: 11 + - area_id: 22 + default_cost: 6 + - process_id: 30 + areas: + - area_id: 11 + default_cost: 5 + - area_id: 22 + default_cost: 6 + + cost: 2 + default_metric: 10 + transmit_delay: 2 + hello_interval: 1 + dead_interval: 2 + retransmit_interval: 2 + weight: 2 + packet_size: 577 + priority: 1 + router_id: 2.2.2.2 + demand_circuit: enable + passive: disable + summary_in: enable + flood_reduction: disable + mtu_ignore: enable + external_out: disable + state: rendered + +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "router ospf 27", +# "area 10 authentication keychain ansi11393", +# "area 10 hello-interval 2", +# "router ospf 26", +# "adjacency stagger 10 20", +# "authentication message-digest keychain ansible1101pass", +# "router ospf 10", +# "authentication keychain ansible_test1102", +# "area 11 default-cost 5", +# "area 11 cost 11", +# "area 22 default-cost 6", +# "router ospf 30", +# "cost 2", +# "weight 2", +# "passive disable", +# "priority 1", +# "flood-reduction disable", +# "default-metric 10", +# "router-id 2.2.2.2", +# "demand-circuit enable", +# "packet-size 577", +# "transmit-delay 2", +# "summary-in enable", +# "external-out disable", +# "dead-interval 2", +# "hello-interval 1", +# "retransmit-interval 2", +# "mtu-ignore enable", +# "area 11 default-cost 5", +# "area 22 default-cost 6" +# ] + + +# Using gathered +# +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# +- name: Gather ospfv2 routes configuration + cisco.iosxr.iosxr_ospfv2: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "authentication": { +# "keychain": "ansible_test1102" +# }, +# "process_id": "10" +# }, +# { +# "adjacency_stagger": { +# "max_adjacency": 20, +# "min_adjacency": 10 +# }, +# "authentication": { +# "message_digest": { +# "keychain": "ansible1101pass" +# } +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "authentication": { +# "keychain": "ansi11393" +# }, +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": "enable", +# "external_out": "disable", +# "flood_reduction": "disable", +# "hello_interval": 1, +# "mtu_ignore": "enable", +# "packet_size": 577, +# "passive": "disable", +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "summary_in": "enable", +# "transmit_delay": 2, +# "weight": 2 +# } +# ] +# } +# +# After state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# Thu Jun 11 16:06:44.406 UTC +# router ospf 10 +# authentication keychain ansible_test1102 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospf 26 +# authentication message-digest keychain ansible1101pass +# adjacency stagger 10 20 +# ! +# router ospf 27 +# area 10 +# authentication keychain ansi11393 +# hello-interval 2 +# ! +# ! +# router ospf 30 +# router-id 2.2.2.2 +# summary-in enable +# external-out disable +# cost 2 +# packet-size 577 +# weight 2 +# passive disable +# priority 1 +# mtu-ignore enable +# flood-reduction disable +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit enable +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# +# + +""" +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. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - "router ospf 30" + - "authentication message-digest keychain 'ansible1101pass'" +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospfv2.ospfv2 import ( + Ospfv2Args, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ospfv2.ospfv2 import ( + Ospfv2, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "rendered", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( + argument_spec=Ospfv2Args.argument_spec, + required_if=required_if, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + ) + result = Ospfv2(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv3.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv3.py new file mode 100644 index 00000000..c4a52e55 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ospfv3.py @@ -0,0 +1,2784 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2020 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_ospfv3 +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_ospfv3 +version_added: 1.1.0 +short_description: Resource module to configure OSPFv3. +description: + - This module manages global ospfv3 configuration on devices running Cisco IOS-XR +author: Rohit Thakur (@rohitthakur2590) +notes: + - This module works with connection C(network_cli). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html) +options: + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config router ospfv3). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + config: + description: A list of ospfv3 process configuration + type: dict + suboptions: + processes: + description: A list of ospfv3 instances configuration + type: list + elements: dict + suboptions: + process_id: + description: The OSPFv3 Process ID + type: str + required: true + address_family_unicast: + description: Enable unicast topology for ipv4 address family + type: bool + authentication: + description: Enable authentication + type: dict + suboptions: + disable: + description: Do not authenticate OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec AH authentication attributes + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + auto_cost: + description: Calculate ospfv3 interface cost according to bandwidth + type: dict + suboptions: + reference_bandwidth: + description: Specify reference bandwidth in megabits per sec + type: int + disable: + description: Assign ospfv3 cost based on interface type + type: bool + bfd: + description: Configure BFD parameters + type: dict + suboptions: + fast_detect: + description: Configure fast detection + type: dict + suboptions: + set: + description: Enable fast detection only + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + minimum_interval: + description: Hello interval in milli-seconds + type: int + multiplier: + description: Detect multiplier + type: int + areas: + description: Configure ospfv3 areas' properties + type: list + elements: dict + suboptions: + area_id: + description: Area ID as IP address or integer + type: str + required: True + authentication: + description: Enable authentication + type: dict + suboptions: + disable: + description: Do not authenticate OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec AH authentication attributes + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + bfd: + description: Configure BFD parameters + type: dict + suboptions: + fast_detect: + description: Configure fast detection + type: dict + suboptions: + set: + description: Enable fast detection only + type: bool + strict_mode: + description: Hold down neighbor session until BFD session is up + type: bool + minimum_interval: + description: Hello interval in milli-seconds + type: int + multiplier: + description: Detect multiplier + type: int + cost: + description: Interface cost + type: int + database_filter: + description: Filter LSAs during synchronization and flooding + type: dict + suboptions: + all_outgoing_lsa: + description: Filter all outgoing LSA + type: bool + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + default_cost: + description: Set the summary default-cost of a NSSA/stub area. Stub's advertised external route metric + type: int + demand_circuit: + description: Enable/Disable ospfv3 demand circuit + type: bool + distrinbute_rib_prefix_list_name: + description: Filter LSAs during synchronization and flooding + type: str + fast_reroute: + description: Specify IP Fast Reroute + type: dict + suboptions: + disabled: + description: Disable IP fast reroute + type: bool + per_link: + description: Specify per-prefix computation + type: dict + suboptions: + information_type: + description: Specify per-link LFA exclusion or FRR LFA candidate information + type: str + choices: ["exclude", "lfa_candidate"] + use_candidate_only: + description: Enable/Disable backup selection from candidate-list only + type: bool + interface: + description: Specify Per-link LFA exclusion information + type: dict + suboptions: + bvi: + description: Specify Bridge-Group Virtual Interface + type: list + elements: int + bundle_ether: + description: Specify Aggregated Ethernet interface(s) + type: list + elements: int + pos_int: + description: Specify Aggregated pos interface(s) + type: list + elements: int + fast_ethernet: + description: Specify FastEthernet/IEEE 802.3 interface(s) + type: list + elements: str + fiftygige: + description: Specify FiftyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fortygige: + description: Specify FortyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fourhundredgige: + description: Specify FourHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + gigabitethernet: + description: Specify GigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + hundredgige: + description: Specify HundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + mgmteth: + description: Specify MgmtEth/IEEE 802.3 interface(s) + type: list + elements: str + multilink: + description: Specify Multilink network interface(s) + type: list + elements: str + pw_ether: + description: Specify PWHE Ethernet Interface + type: list + elements: int + pw_iw: + description: Specify PWHE VC11 IP Interworking Interface + type: list + elements: int + srp: + description: Specify SRP interface(s) + type: list + elements: str + serial: + description: Specify Serial network interface(s) + type: list + elements: str + tengige: + description: Specify TenGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twentyfivegige: + description: Specify TwentyFiveGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twohundredgige: + description: Specify TwoHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + nve: + description: Specify Network Virtualization Endpoint Interface(s) + type: list + elements: int + tunnel_ip: + description: Specify GRE/IPinIP Tunnel Interface(s) + type: list + elements: int + tunnel_ipsec: + description: Specify IPSec Tunnel interface(s) + type: list + elements: int + tunnel_mte: + description: Specify MPLS Traffic Engineering P2MP Tunnel interface(s) + type: list + elements: int + tunnel_mpls: + description: MPLS Transport Protocol Tunnel interface + type: int + per_prefix: + description: Specify per-prefix computation + type: dict + suboptions: + information_type: + description: Specify per_prefix LFA exclusion or FRR LFA candidate information + type: str + choices: ["exclude", "lfa_candidate"] + use_candidate_only: + description: Enable/Disable backup selection from candidate-list only + type: bool + interface: + description: Specify Per-link LFA exclusion information + type: dict + suboptions: + bvi: + description: Specify Bridge-Group Virtual Interface + type: list + elements: int + bundle_ether: + description: Specify Aggregated Ethernet interface(s) + type: list + elements: int + pos_int: + description: Specify Aggregated pos interface(s) + type: list + elements: int + fast_ethernet: + description: Specify FastEthernet/IEEE 802.3 interface(s) + type: list + elements: str + fiftygige: + description: Specify FiftyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fortygige: + description: Specify FortyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fourhundredgige: + description: Specify FourHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + gigabitethernet: + description: Specify GigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + hundredgige: + description: Specify HundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + mgmteth: + description: Specify MgmtEth/IEEE 802.3 interface(s) + type: list + elements: str + multilink: + description: Specify Multilink network interface(s) + type: list + elements: str + pw_ether: + description: Specify PWHE Ethernet Interface + type: list + elements: int + pw_iw: + description: Specify PWHE VC11 IP Interworking Interface + type: list + elements: int + srp: + description: Specify SRP interface(s) + type: list + elements: str + serial: + description: Specify Serial network interface(s) + type: list + elements: str + tengige: + description: Specify TenGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twentyfivegige: + description: Specify TwentyFiveGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twohundredgige: + description: Specify TwoHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + nve: + description: Specify Network Virtualization Endpoint Interface(s) + type: list + elements: int + tunnel_ip: + description: Specify GRE/IPinIP Tunnel Interface(s) + type: list + elements: int + tunnel_ipsec: + description: Specify IPSec Tunnel interface(s) + type: list + elements: int + tunnel_mte: + description: Specify MPLS Traffic Engineering P2MP Tunnel interface(s) + type: list + elements: int + tunnel_mpls: + description: MPLS Transport Protocol Tunnel interface + type: int + flood_reduction: + description: Enable/Disable flood reduction + type: bool + hello_interval: + description: Specify Time between HELLO packets + type: int + instance_id: + description: Specify instance ID + type: int + mtu_ignore: + description: Enable/Disable ignoring of MTU in DBD packets + type: bool + mpls_ldp_sync: + description: Enable/Disable MPLS LDP Sync + type: bool + network: + description: Specify Network type + type: str + choices: ["broadcast", "non-broadcast", "point-to-multipoint", "point-to-point"] + nssa: + description: NSSA settings for the area + type: dict + suboptions: + set: + description: Configure area as NSSA + type: bool + default_information_originate: + description: Originate default Type 7 LSA + type: dict + suboptions: + set: + description: Set nssa to default information originate + type: bool + metric: + description: ospfv3 default metric + type: int + metric_type: + description: Metric type for default routes + type: int + no_redistribution: + description: Do not send redistributed LSAs into NSSA area + type: bool + no_summary: + description: Do not send summary LSAs into NSSA area + type: bool + translate: + description: Translate LSA + type: dict + suboptions: + type7: + description: Translate from Type 7 to Type 5 + type: dict + suboptions: + always: + description: Always translate LSAs + type: bool + required: true + packet_size: + description: Specify limit size of OSPFv3 packets + type: int + passive: + description: Enable/Disable routing updates on an interface + type: bool + prefix_suppression: + description: Hide all transit addresses on this interface + type: bool + priority: + description: Specify Router priority + type: int + ranges: + description: Summarize routes matching address/mask (border routers only) + type: list + elements: dict + suboptions: + address: + description: IP in Prefix format (X:X::X/length) + type: str + required: True + cost: + description: Specify user specified metric for this range + type: int + advertise: + description: Advertise this range (default) + type: bool + not_advertise: + description: DoNotAdvertise this range + type: bool + retransmit_interval: + description: Specify Delay between LSA retransmissions + type: int + stub: + description: Settings for configuring the area as a stub + type: dict + suboptions: + set: + description: Configure the area as a stub + type: bool + no_summary: + description: Do not send summary LSA into stub area + type: bool + transmit_delay: + description: Specify estimated time needed to send link-state update packet + type: int + virtual_link: + description: Define a virtual link + type: list + elements: dict + suboptions: + id: + description: Router-ID of virtual link neighbor (A.B.C.D) + type: str + required: True + authentication: + description: Enable authentication + type: dict + suboptions: + disable: + description: Do not authenticate OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec AH authentication attributes + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + hello_interval: + description: Time between HELLO packets + type: int + retransmit_interval: + description: Delay between LSA retransmissions + type: int + transmit_delay: + description: Link state transmit delay + type: int + encryption: + description: Encrypt and authenticate OSPFv3 packets + type: dict + suboptions: + disable: + description: Do not encrypt OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec ESP encryption and authentication + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + esp: + description: Specify encryption parameters + type: dict + suboptions: + triple_des: + description: This specify the triple DES algorithim + type: dict + suboptions: + key: + description: Cleartext 3DES key + type: str + clear_key: + description: Specify 3DES key in cleartext form + type: str + password_key: + description: Specify 3DES key in encrypted form + type: str + aes: + description: This specify the aes algorithim + type: dict + suboptions: + algorithim_type: + description: Specify the bit encryption for aes algorithim + type: str + choices: ["192", "256"] + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + des: + description: This specify the des algorithim + type: dict + suboptions: + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + null_encryption: + description: Specify null encryption attributes + type: dict + suboptions: + authentication: + description: Specify authentication parameters + type: dict + suboptions: + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + encryption: + description: Encrypt and authenticate OSPFv3 packets + type: dict + suboptions: + disable: + description: Do not encrypt OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec ESP encryption and authentication + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + esp: + description: Specify encryption parameters + type: dict + suboptions: + triple_des: + description: This specify the triple DES algorithim + type: dict + suboptions: + key: + description: Cleartext 3DES key + type: str + clear_key: + description: Specify 3DES key in cleartext form + type: str + password_key: + description: Specify 3DES key in encrypted form + type: str + aes: + description: This specify the aes algorithim + type: dict + suboptions: + algorithim_type: + description: Specify the bit encryption for aes algorithim + type: str + choices: ["192", "256"] + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + des: + description: This specify the des algorithim + type: dict + suboptions: + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + null_encryption: + description: Specify null encryption attributes + type: dict + suboptions: + authentication: + description: Specify authentication parameters + type: dict + suboptions: + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + capability: + description: Enable specific OSPFv3 feature + type: dict + suboptions: + type7: + description: Specify type7 nssa capability + type: dict + suboptions: + prefer: + description: Prefer type7 externals over type5 + type: bool + translate: + description: Translate type7 to type5 + type: bool + cost: + description: Specify Interface cost + type: int + database_filter: + description: Filter LSAs during synchronization and flooding + type: dict + suboptions: + all_outgoing_lsa: + description: Filter all outgoing LSA + type: bool + dead_interval: + description: Interval after which a neighbor is declared dead + type: int + default_information_originate: + description: Control distribution of default information + type: dict + suboptions: + always: + description: Always advertise default route + type: bool + metric: + description: ospfv3 default metric + type: int + metric_type: + description: ospfv3 metric type for default routes + type: int + route_policy: + description: Apply route-policy to default-information origination + type: str + tag: + description: Set tag for default route + type: int + set: + description: Enable distribution of default route + type: bool + default_metric: + description: Set metric of redistributed routes + type: int + demand_circuit: + description: Enable/Disable ospfv3 demand circuit + type: bool + distance: + description: Define an administrative distance + type: dict + suboptions: + admin_distance: + description: Administrative distance + type: int + ospfv3_distance: + description: ospfv3 administrative distance + type: dict + suboptions: + external: + description: Distance for external routes + type: int + inter_area: + description: Distance for inter-area routes + type: int + intra_area: + description: Distance for intra-area routes + type: int + distribute_list: + description: Filter prefixes to/from RIB + type: dict + suboptions: + prefix_list: + description: Filter prefixes based on an IPv6 prefix-list + type: list + elements: str + suboptions: + name: + description: Specify Prefix-list name + type: str + in: + description: Filter prefixes installed to RIB + type: bool + out: + description: Filter prefixes redistributed from RIB + type: bool + encryption: + description: Encrypt and authenticate OSPFv3 packets + type: dict + suboptions: + disable: + description: Do not encrypt OSPFv3 packets + type: bool + default: false + ipsec: + description: Specify IPSec ESP encryption and authentication + type: dict + suboptions: + spi: + description: Specify the Security Parameter Index value + type: int + esp: + description: Specify encryption parameters + type: dict + suboptions: + triple_des: + description: This specify the triple DES algorithim + type: dict + suboptions: + key: + description: Cleartext 3DES key + type: str + clear_key: + description: Specify 3DES key in cleartext form + type: str + password_key: + description: Specify 3DES key in encrypted form + type: str + aes: + description: This specify the aes algorithim + type: dict + suboptions: + algorithim_type: + description: Specify the bit encryption for aes algorithim + type: str + choices: ["192", "256"] + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + des: + description: This specify the des algorithim + type: dict + suboptions: + key: + description: Cleartext AES key + type: str + clear_key: + description: Specify AES key in cleartext form + type: str + password_key: + description: Specify AES key in encrypted form + type: str + null_encryption: + description: Specify null encryption attributes + type: dict + suboptions: + authentication: + description: Specify authentication parameters + type: dict + suboptions: + algorithim_type: + description: Specify the type of algorithim + type: str + choices: ["md5", "sha1"] + key: + description: Specify key + type: str + clear_key: + description: Specify key in cleartext form + type: str + password_key: + description: Specify key in encrypted form + type: str + fast_reroute: + description: Specify IP Fast Reroute + type: dict + suboptions: + disabled: + description: Disable IP fast reroute + type: bool + per_link: + description: Specify per-prefix computation + type: dict + suboptions: + information_type: + description: Specify per-link LFA exclusion or FRR LFA candidate information + type: str + choices: ["exclude", "lfa_candidate"] + use_candidate_only: + description: Enable/Disable backup selection from candidate-list only + type: bool + interface: + description: Specify Per-link LFA exclusion information + type: dict + suboptions: + bvi: + description: Specify Bridge-Group Virtual Interface + type: list + elements: int + bundle_ether: + description: Specify Aggregated Ethernet interface(s) + type: list + elements: int + pos_int: + description: Specify Aggregated pos interface(s) + type: list + elements: int + fast_ethernet: + description: Specify FastEthernet/IEEE 802.3 interface(s) + type: list + elements: str + fiftygige: + description: Specify FiftyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fortygige: + description: Specify FortyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fourhundredgige: + description: Specify FourHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + gigabitethernet: + description: Specify GigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + hundredgige: + description: Specify HundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + mgmteth: + description: Specify MgmtEth/IEEE 802.3 interface(s) + type: list + elements: str + multilink: + description: Specify Multilink network interface(s) + type: list + elements: str + pw_ether: + description: Specify PWHE Ethernet Interface + type: list + elements: int + pw_iw: + description: Specify PWHE VC11 IP Interworking Interface + type: list + elements: int + srp: + description: Specify SRP interface(s) + type: list + elements: str + serial: + description: Specify Serial network interface(s) + type: list + elements: str + tengige: + description: Specify TenGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twentyfivegige: + description: Specify TwentyFiveGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twohundredgige: + description: Specify TwoHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + nve: + description: Specify Network Virtualization Endpoint Interface(s) + type: list + elements: int + tunnel_ip: + description: Specify GRE/IPinIP Tunnel Interface(s) + type: list + elements: int + tunnel_ipsec: + description: Specify IPSec Tunnel interface(s) + type: list + elements: int + tunnel_mte: + description: Specify MPLS Traffic Engineering P2MP Tunnel interface(s) + type: list + elements: int + tunnel_mpls: + description: MPLS Transport Protocol Tunnel interface + type: int + per_prefix: + description: Specify per-prefix computation + type: dict + suboptions: + information_type: + description: Specify per_prefix LFA exclusion or FRR LFA candidate information + type: str + choices: ["exclude", "lfa_candidate"] + use_candidate_only: + description: Enable/Disable backup selection from candidate-list only + type: bool + interface: + description: Specify Per-link LFA exclusion information + type: dict + suboptions: + bvi: + description: Specify Bridge-Group Virtual Interface + type: list + elements: int + bundle_ether: + description: Specify Aggregated Ethernet interface(s) + type: list + elements: int + post_int: + description: Specify Aggregated pos interface(s) + type: list + elements: int + fast_ethernet: + description: Specify FastEthernet/IEEE 802.3 interface(s) + type: list + elements: str + fiftygige: + description: Specify FiftyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fortygige: + description: Specify FortyGigE/IEEE 802.3 interface(s) + type: list + elements: str + fourhundredgige: + description: Specify FourHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + gigabitethernet: + description: Specify GigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + hundredgige: + description: Specify HundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + mgmteth: + description: Specify MgmtEth/IEEE 802.3 interface(s) + type: list + elements: str + multilink: + description: Specify Multilink network interface(s) + type: list + elements: str + pw_ether: + description: Specify PWHE Ethernet Interface + type: list + elements: int + pw_iw: + description: Specify PWHE VC11 IP Interworking Interface + type: list + elements: int + srp: + description: Specify SRP interface(s) + type: list + elements: str + serial: + description: Specify Serial network interface(s) + type: list + elements: str + tengige: + description: Specify TenGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twentyfivegige: + description: Specify TwentyFiveGigabitEthernet/IEEE 802.3 interface(s) + type: list + elements: str + twohundredgige: + description: Specify TwoHundredGigE/IEEE 802.3 interface(s) + type: list + elements: str + nve: + description: Specify Network Virtualization Endpoint Interface(s) + type: list + elements: int + tunnel_ip: + description: Specify GRE/IPinIP Tunnel Interface(s) + type: list + elements: int + tunnel_ipsec: + description: Specify IPSec Tunnel interface(s) + type: list + elements: int + tunnel_mte: + description: Specify MPLS Traffic Engineering P2MP Tunnel interface(s) + type: list + elements: int + tunnel_mpls: + description: MPLS Transport Protocol Tunnel interface + type: int + flood_reduction: + description: Enable/Disable flood reduction + type: bool + graceful_restart: + description: Enable Graceful-Restart + type: dict + suboptions: + set: + description: Set graceful restart + type: bool + helper_disable: + description: Disable router's helper support level + type: bool + min_interval: + description: Minimum interval between Graceful Restarts + type: int + max_interval: + description: Maximum route lifetime following restart + type: int + hello_interval: + description: Specify Time between HELLO packets + type: int + ignore_mospf_type6_lsa: + description: Ignore MOSPF Type 6 LSA + type: bool + instance_id: + description: Specify instance ID + type: int + log_adjacency_changes: + description: Log adjacency state changes + type: dict + suboptions: + set: + description: Set log adjacency + type: bool + disable: + description: Disable log adjacency changes + type: bool + detail: + description: Log all state changes + type: bool + maximum: + description: Set OSPFv3 limits + type: dict + suboptions: + interfaces: + description: Specify limit for number of interfaces + type: int + paths: + description: Specify limit for number of paths + type: int + redistributed_prefixes: + description: Specify limit for number of redistributed prefixes + type: int + mpls_ldp_sync: + description: Enable/Disable MPLS LDP Sync + type: bool + mtu_ignore: + description: Enable/Disable ignoring of MTU in DBD packets + type: bool + network: + description: Specify Network type + type: str + choices: ["broadcast", "non-broadcast", "point-to-multipoint", "point-to-point"] + nsr: + description: Enable/Disable NSR for all VRFs in this process + type: bool + packet_size: + description: Specify limit size of OSPFv3 packets + type: int + passive: + description: Enable/Disable routing updates on an interface + type: bool + prefix_suppression: + description: Hide all transit addresses on this interface + type: bool + priority: + description: Specify Router priority + type: int + protocol_shutdown: + description: Gracefully shutdown the OSPFv3 protocol + type: bool + redistribute: + description: Redistribute information from another routing Protocol + type: dict + suboptions: + application: + description: Specify application routes + type: list + elements: dict + suboptions: + id: + description: OnePK Application name + type: str + required: true + set: + description: Set application route + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + bgp: + description: Specify bgp routes + type: list + elements: dict + suboptions: + id: + description: BGP process name + type: int + required: true + set: + description: Set bgp route number + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + preserved_med: + description: Specify preserve med of BGP routes + type: str + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + connected: + description: Specify connected routes + type: dict + suboptions: + set: + description: Set connected route + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + eigrp: + description: Specify eigrp routes + type: list + elements: dict + suboptions: + id: + description: EIGRP process name + type: int + required: true + set: + description: Set bgp route number + type: bool + match: + description: Redistribution of EIGRP routes + type: str + choices: ["external", "internal"] + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + isis: + description: Specify IS-IS routes + type: list + elements: dict + suboptions: + id: + description: IS-IS name + type: str + required: true + set: + description: Set IS-IS route number + type: bool + level: + description: Specify IS-IS level routes + type: str + choices: ["level-1", "level-1-2", "level-2"] + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + mobile: + description: Specify mobile routes + type: dict + suboptions: + set: + description: Set mobile route number + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + ospfv3: + description: Specify ospfv3 routes + type: list + elements: dict + suboptions: + id: + description: OSPFv3 process name + type: str + required: true + set: + description: Set ospfv3 route number + type: bool + match: + description: Redistribution of OSPFv3 routes + type: dict + suboptions: + external: + description: Redistribute OSPFv3 external routes + type: int + choices: ["1", "2"] + nssa_external: + description: Redistribute NSSA OSPFv3 external routes + type: int + choices: ["1", "2"] + internal: + description: Redistribute OSPFv3 internal routes + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + static: + description: Specify static routes + type: dict + suboptions: + set: + description: Set static route + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + subscriber: + description: Specify subscriber routes + type: dict + suboptions: + set: + description: Set static route + type: bool + metric: + description: Specify metric for redistributed routes + type: int + metric_type: + description: Specify OSPFv3 exterior metric type for redistributed routes + type: int + route_policy: + description: Apply route policy to redistribution + type: str + tag: + description: Set tag for routes redistributed into OSPFv3 + type: int + retransmit_interval: + description: Delay between LSA retransmissions + type: int + router_id: + description: ospfv3 router-id in IPv4 address format (A.B.C.D) + type: str + spf_prefix_priority: + description: Specify SPF configuration + type: dict + suboptions: + disable: + description: Disable SPF prefix priority + type: bool + route_policy: + description: Specify the route-policy to prioritize route install + type: list + elements: dict + suboptions: + name: + description: Specify name of the policy + type: str + value: + description: Specify parameter values for the policy () + type: str + stub_router: + description: Enter stub router configuration submode + type: dict + suboptions: + router_lsa: + description: Modify self originated router LSAs + type: dict + suboptions: + advertise_with: + description: Advertise LSAs with specified type + type: str + choices: ["max-metric", "r-bit", "v6-bit"] + always: + description: Force ospfv3 stub router mode unconditionally + type: bool + external_lsa: + description: Override External LSA metric in stub router mode + type: dict + suboptions: + set: + description: Set external lsa + type: bool + metric: + description: Metric to use while in stub router mode + type: int + include_stub: + description: Set maximum metric for stub links in stub router mode + type: bool + on_proc_migration: + description: Enter stub router mode on ospfv3 process migration + type: int + on_proc_restart: + description: Enter stub router mode on ospfv3 process restart + type: int + on_startup: + description: Enter stub router mode on startup + type: dict + suboptions: + time: + description: Time in seconds to stay in stub router mode + type: int + wait_for_bgp: + description: Exit stub router mode when BGP converges + type: bool + on_switchover: + description: Enter stub router mode on RP switchover + type: int + summary_lsa: + description: Override Summary LSA metric in stub router mode + type: dict + suboptions: + set: + description: Enable summary LSA + type: bool + metric: + description: Metric to use while in stub router mode + type: int + summary_prefix: + description: Configure IP address summaries + type: list + elements: dict + suboptions: + prefix: + description: IP summary address/mask (A.B.C.D/prefix) + type: str + required: True + not_advertise: + description: Suppress routes that match the specified prefix/mask pair + type: bool + tag: + description: Set tag + type: int + timers: + description: Adjust routing timers + type: dict + suboptions: + lsa_arrival: + description: Specify LSA arrival timers + type: int + pacing: + description: Specify pacing timers + type: dict + suboptions: + flood: + description: Flood pacing timer + type: int + lsa_group: + description: LSA group pacing timer + type: int + retransmission: + description: LSA group pacing timer + type: int + throttle: + description: Adjust throttle timers + type: dict + suboptions: + lsa: + description: Specify LSA throttle timers + type: dict + suboptions: + all_lsa_initial: + description: Delay to generate first occurrence of LSA in milliseconds + type: int + all_lsa_minimum: + description: Minimum delay between originating the same LSA in milliseconds + type: int + spf: + description: Specify SPF throttle timers + type: dict + suboptions: + spf_initial: + description: Delay to generate first occurrence of SPF in ms + type: int + spf_minimum: + description: Minimum delay between originating the same SPF in ms + type: int + trace: + description: Specify OSPF tracing options + type: dict + suboptions: + size: + description: Delete existing buffer and create one with N entries + type: str + value: + description: Specify trace entry + type: int + transmit_delay: + description: Estimated time needed to send link-state update packet + type: int + state: + description: + - The state the configuration should be left in + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged +""" +EXAMPLES = """ +# Using merged + +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospfv3 +# Thu Jun 11 15:54:44.569 UTC +# % No such configuration item(s) +# + +- name: Merge provided OSPFv3 configuration with the existing configuration + cisco.iosxr.iosxr_ospfv3: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + - process_id: 26 + authentication: + disable: true + - process_id: 10 + areas: + - area_id: 11 + default_cost: 5 + cost: 11 + - area_id: 22 + default_cost: 6 + - process_id: 30 + areas: + - area_id: 11 + default_cost: 5 + - area_id: 22 + default_cost: 6 + cost: 2 + default_metric: 10 + transmit_delay: 2 + hello_interval: 1 + dead_interval: 2 + retransmit_interval: 2 + packet_size: 577 + priority: 1 + router_id: '2.2.2.2' + demand_circuit: true + mtu_ignore: true + state: merged + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": {} +# +# "commands": [ +# "router ospfv3 10", +# "area 11 default-cost 5", +# "area 11 cost 11", +# "area 22 default-cost 6", +# "router ospfv3 26", +# "authentication disable", +# "router ospfv3 27", +# "area 10 hello-interval 2", +# "router ospfv3 30", +# "cost 2", +# "priority 1", +# "default-metric 10", +# "router-id 2.2.2.2", +# "demand-circuit", +# "packet-size 577", +# "transmit-delay 2", +# "dead-interval 2", +# "hello-interval 1", +# "retransmit-interval 2", +# "mtu-ignore", +# "area 11 default-cost 5", +# "area 22 default-cost 6" +# ] +# +# "after": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +# +# ------------ +# After state +# ------------ +# +# RP/0/RP0/CPU0:anton#show running-config router ospfv3 +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! + + + +# Using replaced +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! + +- name: Replace OSPFv3 routes configurations from the device + cisco.iosxr.iosxr_ospfv3: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + - area_id: 20 + cost: 2 + default_cost: 2 + - process_id: 26 + authentication: + disable: true + state: replaced + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +# "commands": [ +# "router ospfv3 27", +# "area 20 default-cost 2", +# "area 20 cost 2" +# ] +# +# "after": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton(config)#do show running-config router ospfv3 +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# cost 2 +# default-cost 2 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! + + +- name: Override existing OSPFv3 configurations from the device + cisco.iosxr.iosxr_ospfv3: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + authentication: + disable: true + - area_id: 20 + cost: 2 + default_cost: 2 + authentication: + disable: true + - process_id: 26 + areas: + - area_id: 10 + hello_interval: 2 + authentication: + disable: true + state: overridden + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +# "commands": [ +# "router ospfv3 10", +# "no area 11 default-cost 5", +# "no area 11 cost 11", +# "no area 22 default-cost 6", +# "router ospfv3 30", +# "no cost 2", +# "no priority 1", +# "no default-metric 10", +# "no router-id 2.2.2.2", +# "no demand-circuit", +# "no packet-size 577", +# "no transmit-delay 2", +# "no dead-interval 2", +# "no hello-interval 1", +# "no retransmit-interval 2", +# "no mtu-ignore", +# "no area 11 default-cost 5", +# "no area 22 default-cost 6", +# "router ospfv3 26", +# "area 10 hello-interval 4" +# ] +# +# "after": { +# "processes": [ +# { +# "process_id": "10" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 4 +# } +# ], +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "process_id": "30" +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospfv3 +# router ospfv3 10 +# area 11 +# ! +# area 22 +# ! +# ! +# router ospfv3 26 +# authentication disable +# area 10 +# hello-interval 4 +# ! +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# cost 2 +# default-cost 2 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# area 11 +# ! +# area 22 +# ! +# ! + + + +# Using deleted +# +# ------------ +# Before state +# ------------ +# +# +# RP/0/RP0/CPU0:anton#show running-config router ospfv3 +# router ospfv3 10 +# area 11 +# ! +# area 22 +# ! +# ! +# router ospfv3 26 +# authentication disable +# area 10 +# hello-interval 4 +# ! +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# cost 2 +# default-cost 2 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# area 11 +# ! +# area 22 +# ! +# ! + +- name: Deleted existing OSPFv3 configurations from the device + cisco.iosxr.iosxr_ospfv3: + config: + processes: + - process_id: '10' + - process_id: '26' + - process_id: '27' + - process_id: '30' + state: deleted + +# +# +# ------------------------ +# Module Execution Result +# ------------------------ +# +# "before": { +# "processes": [ +# { +# "process_id": "10" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 4 +# } +# ], +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# }, +# { +# "area_id": "20", +# "cost": 2, +# "default_cost": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "process_id": "30" +# } +# ] +# }, +# +# "commands": [ +# "router ospfv3 26", +# "no authentication disable", +# "no area 10 hello-interval 4", +# "router ospfv3 27", +# "no area 10 hello-interval 2", +# "no area 20 default-cost 2", +# "no area 20 cost 2" +# ] +# +# "after": { +# "processes": [ +# { +# "process_id": "10" +# }, +# { +# "process_id": "26" +# }, +# { +# "process_id": "27" +# }, +# { +# "process_id": "30" +# } +# ] +# } +# +# +# ----------- +# After state +# ----------- +# +# RP/0/RP0/CPU0:anton(config)#show running-config router ospfv3 +# router ospfv3 10 +# ! +# router ospfv3 26 +# ! +# router ospfv3 27 +# ! +# router ospfv3 30 +# ! + + +# Using parsed +# parsed.cfg +# ------------ +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# ! +# router ospfv3 30 +# router-id 2.2.2.2 +# cost 2 +# packet-size 577 +# priority 1 +# mtu-ignore +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +- name: Parsed the device configuration to get output commands + cisco.iosxr.iosxr_ospfv3: + running_config: "{{ lookup('file', './parsed.cfg') }}" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +# Using rendered +# +# +- name: Render the commands for provided configuration + cisco.iosxr.iosxr_ospfv3: + config: + processes: + - process_id: 27 + areas: + - area_id: 10 + hello_interval: 2 + - process_id: 26 + authentication: + disable: true + - process_id: 10 + areas: + - area_id: 11 + default_cost: 5 + cost: 11 + - area_id: 22 + default_cost: 6 + - process_id: 30 + areas: + - area_id: 11 + default_cost: 5 + - area_id: 22 + default_cost: 6 + cost: 2 + default_metric: 10 + transmit_delay: 2 + hello_interval: 1 + dead_interval: 2 + retransmit_interval: 2 + packet_size: 577 + priority: 1 + router_id: '2.2.2.2' + demand_circuit: true + mtu_ignore: true + state: rendered + +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "router ospfv3 27", +# "area 10 hello-interval 2", +# "router ospfv3 26", +# "authentication disable", +# "router ospfv3 10", +# "area 11 default-cost 5", +# "area 11 cost 11", +# "area 22 default-cost 6", +# "router ospfv3 30", +# "cost 2", +# "priority 1", +# "default-metric 10", +# "router-id 2.2.2.2", +# "demand-circuit", +# "packet-size 577", +# "transmit-delay 2", +# "dead-interval 2", +# "hello-interval 1", +# "retransmit-interval 2", +# "mtu-ignore", +# "area 11 default-cost 5", +# "area 22 default-cost 6" +# ] + + +# Using gathered +# +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:anton#show running-config router ospf +# router ospfv3 10 +# area 11 +# cost 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! +# router ospfv3 26 +# authentication disable +# area 10 +# ! +# ! +# router ospfv3 27 +# area 10 +# hello-interval 2 +# ! +# area 20 +# ! +# area 30 +# ! +# ! +# router ospfv3 30 +# cost 2 +# priority 1 +# mtu-ignore +# packet-size 577 +# dead-interval 2 +# retransmit-interval 2 +# demand-circuit +# hello-interval 1 +# transmit-delay 2 +# router-id 2.2.2.2 +# default-metric 10 +# area 11 +# default-cost 5 +# ! +# area 22 +# default-cost 6 +# ! +# ! + +- name: Gather ospfv3 routes configuration + cisco.iosxr.iosxr_ospfv3: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": { +# "processes": [ +# { +# "areas": [ +# { +# "area_id": "11", +# "cost": 11, +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "process_id": "10" +# }, +# { +# "authentication": { +# "disable": true +# }, +# "process_id": "26" +# }, +# { +# "areas": [ +# { +# "area_id": "10", +# "hello_interval": 2 +# } +# ], +# "process_id": "27" +# }, +# { +# "areas": [ +# { +# "area_id": "11", +# "default_cost": 5 +# }, +# { +# "area_id": "22", +# "default_cost": 6 +# } +# ], +# "cost": 2, +# "dead_interval": 2, +# "default_metric": 10, +# "demand_circuit": true, +# "hello_interval": 1, +# "mtu_ignore": true, +# "packet_size": 577, +# "priority": 1, +# "process_id": "30", +# "retransmit_interval": 2, +# "router_id": "2.2.2.2", +# "transmit_delay": 2 +# } +# ] +# } +# +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ospfv3.ospfv3 import ( + Ospfv3Args, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ospfv3.ospfv3 import ( + Ospfv3, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Ospfv3Args.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Ospfv3(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ping.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ping.py new file mode 100644 index 00000000..9861cc09 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_ping.py @@ -0,0 +1,176 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_ping +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_ping +short_description: Tests reachability using ping from IOSXR switch. +description: +- Tests reachability using ping from switch to a remote destination. +- For a general purpose network module, see the L(net_ping,https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/net_ping_module.html) + module. +- For Windows targets, use the L(win_ping,https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_ping_module.html) + module instead. +- For targets running Python, use the L(ping,https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ping_module.html) + module instead. +notes: +- Tested against IOSXR 7.2.2. +- This module works with connection C(network_cli). +- For a general purpose network module, see the L(net_ping,https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/net_ping_module.html) + module. +- For Windows targets, use the L(win_ping,https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_ping_module.html) + module instead. +- For targets running Python, use the L(ping,https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ping_module.html) module instead. + +author: Sagar Paul (@KB-perByte) +options: + count: + description: + - Repeat count the number of packets to send. + type: int + afi: + description: + - Define echo type ipv4 or ipv6. + choices: + - ipv4 + - ipv6 + default: ipv4 + type: str + dest: + description: + - The IP Address or hostname (resolvable by switch) of the remote node. + required: true + type: str + df_bit: + description: + - Set the DF bit in IP-header. + default: false + type: bool + sweep: + description: + - Sweep ping. + default: false + type: bool + validate: + description: + - Validate return packet. + default: false + type: bool + source: + description: + - Source address or source interface. + type: str + size: + description: + - Datagram size the size of packets to send. + type: int + state: + description: + - Determines if the expected result is success or fail. + choices: + - absent + - present + default: present + type: str + vrf: + description: + - The VRF to use for forwarding. + type: str +""" + +EXAMPLES = """ +- name: Test reachability to 198.51.100.251 using default vrf + cisco.iosxr.iosxr_ping: + dest: 198.51.100.251 + +- name: Test reachability to 198.51.100.252 using prod vrf + cisco.iosxr.iosxr_ping: + dest: 198.51.100.252 + vrf: prod + afi: ipv4 + +- name: Test unreachability to 198.51.100.253 using default vrf + cisco.iosxr.iosxr_ping: + dest: 198.51.100.253 + state: absent + +- name: Test reachability to 198.51.100.250 using prod vrf and setting count and source + cisco.iosxr.iosxr_ping: + dest: 198.51.100.250 + source: loopback0 + vrf: prod + count: 20 + +- name: Test reachability to 198.51.100.249 using df-bit and size + cisco.iosxr.iosxr_ping: + dest: 198.51.100.249 + df_bit: true + size: 1400 + +- name: Test reachability to ipv6 address + cisco.iosxr.iosxr_ping: + dest: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff + afi: ipv6 +""" + +RETURN = """ +commands: + description: Show the command sent. + returned: always + type: list + sample: ["ping vrf prod 198.51.100.251 count 20 source loopback0"] +packet_loss: + description: Percentage of packets lost. + returned: always + type: str + sample: "0%" +packets_rx: + description: Packets successfully received. + returned: always + type: int + sample: 20 +packets_tx: + description: Packets successfully transmitted. + returned: always + type: int + sample: 20 +rtt: + description: Show RTT stats. + returned: always + type: dict + sample: {"avg": 2, "max": 8, "min": 1} +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.ping.ping import ( + PingArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ping.ping import Ping + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule(argument_spec=PingArgs.argument_spec) + + result = Ping(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_prefix_lists.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_prefix_lists.py new file mode 100644 index 00000000..1fccc852 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_prefix_lists.py @@ -0,0 +1,1115 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_prefix_lists +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: iosxr_prefix_lists +short_description: Resource module to configure prefix lists. +description: +- This module manages prefix-lists configuration on devices running Cisco IOSXR. +version_added: 2.3.0 +notes: +- Tested against IOSXR 7.0.2. +- This module works with connection C(network_cli). +author: Ashwini Mhatre (@amhatre) +options: + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the Iosxr device by + executing the command B(show running-config prefix-list). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + config: + description: A list of prefix-lists configuration. + type: list + elements: dict + suboptions: + afi: + description: + - The Address Family Identifier (AFI) for the prefix-lists. + type: str + choices: ["ipv4", "ipv6"] + prefix_lists: + description: List of prefix-list configurations. + type: list + elements: dict + suboptions: + name: + description: Name of the prefix-list. + type: str + entries: + description: List of configurations for the specified prefix-list + type: list + elements: dict + suboptions: + sequence: + description: Sequence Number. + type: int + action: + description: Prefix-List permit or deny. + type: str + choices: ["permit", "deny", "remark"] + description: + description: Description of the prefix list. only applicable for action "remark". + type: str + prefix: + description: IP or IPv6 prefix in A.B.C.D/LEN or A:B::C:D/LEN format. only applicable for action "permit" and "deny" + type: str + eq: + description: Exact prefix length to be matched. + type: int + ge: + description: Minimum prefix length to be matched. + type: int + le: + description: Maximum prefix length to be matched. + type: int + state: + description: + - The state the configuration should be left in. + - Refer to examples for more details. + - With state I(replaced), for the listed prefix-lists, + sequences that are in running-config but not in the task are negated. + - With state I(overridden), all prefix-lists that are in running-config but + not in the task are negated. + - Please refer to examples for more details. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - parsed + - gathered + - rendered + default: merged +""" + +EXAMPLES = """ +# Using merged +# Before state +#RP/0/0/CPU0:10#show running-config +#Thu Feb 4 09:38:36.245 UTC +#% No such configuration item(s) +#RP/0/0/CPU0:10# +# +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_prefix_lists: + state: merged + config: + - afi: ipv6 + prefix_lists: + - name: pl_1 + entries: + - prefix: 2001:db8:1234::/48 + action: deny + sequence: 1 + - name: pl_2 + entries: + - sequence: 2 + action: remark + description: TEST_PL_2_REMARK + - afi: ipv4 + prefix_lists: + - name: pl1 + entries: + - sequence: 3 + action: remark + description: TEST_PL1_2_REMARK + - sequence: 4 + action: permit + prefix: 10.0.0.0/24 + - name: pl2 + entries: + - sequence: 5 + action: remark + description: TEST_PL2_REMARK + - name: pl3 + entries: + - sequence: 6 + action: permit + prefix: 35.0.0.0/8 + eq: 0 + +# +# After state: +# +#RP/0/0/CPU0:10#show running-config +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +# ! +# ipv4 prefix-list pl3 +# 6 permit 35.0.0.0/8 eq 0 +# ! + +#Module execution +# +# "after": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL_2_REMARK", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": "35.0.0.0/8", +# "sequence": 6, +# "eq": 0 +# } +# ], +# "name": "pl3" +# }, +# ] +# } +# ], +# "before": [], +# "changed": true, +# "commands": [ +# "ipv6 prefix-list pl_1 1 deny 2001:db8:1234::/48", +# "ipv6 prefix-list pl_2 2 remark TEST_PL_2_REMARK", +# "ipv4 prefix-list pl1 3 remark TEST_PL1_2_REMARK", +# "ipv4 prefix-list pl1 4 permit 10.0.0.0/24", +# "ipv4 prefix-list pl2 5 remark TEST_PL2_REMARK" +# "ipv4 prefix-list pl3 6 permit 35.0.0.0/8 eq 0" +# ] +#----------------------------------------------------------------------- +# Using replaced: +# -------------- +# Before state +#RP/0/0/CPU0:10#show running-config +# +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +# ! +# +# +- name: Replace device configurations of listed prefix lists with provided configurations + register: result + cisco.iosxr.iosxr_prefix_lists: &id001 + config: + - afi: ipv4 + prefix_lists: + - name: pl1 + entries: + - sequence: 3 + action: permit + prefix: 10.0.0.0/24 + - afi: ipv6 + prefix_lists: + - name: pl_1 + entries: + - prefix: 2001:db8:1234::/48 + action: permit + sequence: 1 + - name: pl_2 + entries: + - sequence: 2 + action: remark + description: TEST_PL1_2 + state: replaced +# After state: +#RP/0/0/CPU0:10#show running-config +# +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL1_2 +# ! +# ipv4 prefix-list pl1 +# 3 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +# +# Module Execution: +# +# "after": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 3 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# } +# ] +# } +# ], +# "before": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL_2_REMARK", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ipv4 prefix-list pl1 3 remark TEST_PL1_2_REMARK", +# "no ipv4 prefix-list pl1 4 permit 10.0.0.0/24", +# "ipv4 prefix-list pl1 3 permit 10.0.0.0/24", +# "ipv6 prefix-list pl_2 2 remark TEST_PL1_2" +# ], +# "invocation": { +# "module_args": { +# "config": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": null, +# "prefix": "10.0.0.0/24", +# "sequence": 3 +# } +# ], +# "name": "pl1" +# } +# ] +# }, +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "permit", +# "description": null, +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2", +# "prefix": null, +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# } +# ], +# "running_config": null, +# "state": "replaced" +# } +# } +# } +#------------------------------------------------------------------ +# Using deleted: +# ------------- +# Before state: +#RP/0/0/CPU0:10#show running-config +# +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +# ipv4 prefix-list pl3 +# 6 permit 35.0.0.0/8 eq 0 + +- name: Delete all prefix-lists from the device + cisco.iosxr.iosxr_prefix_lists: + state: deleted + +# After state: +#RP/0/0/CPU0:10#show running-config +# +# +# Module Execution: +# +# "after": [], +# "before": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 3 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": " 35.0.0.0/8", +# "sequence": 6, +# "eq": 0 +# } +# ], +# "name": "pl3" +# }, +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ipv6 prefix-list pl_1", +# "no ipv6 prefix-list pl_2", +# "no ipv4 prefix-list pl1", +# "no ipv4 prefix-list pl2" +# "no ipv4 prefix-list pl3" +# ], +# "invocation": { +# "module_args": { +# "config": null, +# "running_config": null, +# "state": "deleted" +# } +# } +# } +#--------------------------------------------------------------------------------- +# +# using gathered: +# -------------- +# Before state: +#RP/0/0/CPU0:10#show running-config +# +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +#! +# ipv4 prefix-list pl3 +# 6 permit 35.0.0.0/8 eq 0 +#! +- name: Gather ACL interfaces facts using gathered state + cisco.iosxr.iosxr_prefix_lists: + state: gathered +# +# Module Execution: +# +# "gathered": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL_2_REMARK", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": "35.0.0.0/8", +# "sequence": 6, +# "eq": 0 +# } +# ], +# "name": "pl3" +# }, +# ] +# } +# ], +# "changed": false, +#-------------------------------------------------------------------------- +# Using parsed: +# -------------- +# +# parsed.cfg +#------------------------------ +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +#! +# ipv4 prefix-list pl3 +# 6 permit 35.0.0.0/8 eq 0 +# +# +- name: Parse externally provided Prefix_lists config to agnostic model + cisco.iosxr.iosxr_prefix_lists: + running_config: "{{ lookup('file', './fixtures/parsed.cfg') }}" + state: parsed +# +# Module execution: +#"parsed": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL_2_REMARK", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# }, +# { +# "entries": [ +# { +# "action": "permit", +# "prefix": "35.0.0.0/8", +# "sequence": 6, +# "eq": 0 +# } +# ], +# "name": "pl3" +# }, +# ] +# } +# ] +# +#---------------------------------------------------------------------------- +# Using rendered: +# -------------- +# +- name: Render platform specific commands from task input using rendered state + register: result + cisco.iosxr.iosxr_prefix_lists: + config: + - afi: ipv6 + prefix_lists: + - name: pl_1 + entries: + - prefix: 2001:db8:1234::/48 + action: deny + sequence: 1 + - name: pl_2 + entries: + - sequence: 2 + action: remark + description: TEST_PL_2_REMARK + - afi: ipv4 + prefix_lists: + - name: pl1 + entries: + - sequence: 3 + action: remark + description: TEST_PL1_2_REMARK + - sequence: 4 + action: permit + prefix: 10.0.0.0/24 + - name: pl2 + entries: + - sequence: 5 + action: remark + description: TEST_PL2_REMARK + - sequence: 6 + action: permit + prefix: 35.0.0.0/8 + eq: 0 + + state: rendered +# After state: +# Module Execution: +# "rendered": [ +# "ipv6 prefix-list pl_1 1 deny 2001:db8:1234::/48", +# "ipv6 prefix-list pl_2 2 remark TEST_PL_2_REMARK", +# "ipv4 prefix-list pl1 3 remark TEST_PL1_2_REMARK", +# "ipv4 prefix-list pl1 4 permit 10.0.0.0/24", +# "ipv4 prefix-list pl2 5 remark TEST_PL2_REMARK", +# "ipv4 prefix-list pl2 6 permit 35.0.0.0/8 eq 0" +# ] +# +#--------------------------------------------------------------------------------- +# Using overridden: +# -------------- +# Before state: +#RP/0/0/CPU0:10#show running-config +# +# ipv6 prefix-list pl_1 +# 1 deny 2001:db8:1234::/48 +# ! +# ipv6 prefix-list pl_2 +# 2 remark TEST_PL_2_REMARK +# ! +# ipv4 prefix-list pl1 +# 3 remark TEST_PL1_2_REMARK +# 4 permit 10.0.0.0/24 +# ! +# ipv4 prefix-list pl2 +# 5 remark TEST_PL2_REMARK +# +- name: Overridde all Prefix_lists configuration with provided configuration + cisco.iosxr.iosxr_prefix_lists: + config: + - afi: ipv4 + prefix_lists: + - name: pl3 + entries: + - sequence: 3 + action: remark + description: TEST_PL1_3_REMARK + - sequence: 4 + action: permit + prefix: 10.0.0.0/24 + - sequence: 6 + action: permit + prefix: 35.0.0.0/8 + eq: 0 + state: overridden + +# After state: +#RP/0/0/CPU0:10#show running-config +# +#ipv4 prefix-list pl3 +# 3 remark TEST_PL1_3_REMARK +# 4 permit 10.0.0.0/24 +# 6 permit 35.0.0.0/8 eq 0 +# ! +#! +# # Module Execution: +# "after": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_3_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# }, +# { +# "action": "permit", +# "prefix": "35.0.0.0/8", +# "sequence": 6, +# "eq": 0 +# } +# ], +# "name": "pl3" +# } +# ] +# } +# ], +# "before": [ +# { +# "afi": "ipv6", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "deny", +# "prefix": "2001:db8:1234::/48", +# "sequence": 1 +# } +# ], +# "name": "pl_1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL_2_REMARK", +# "sequence": 2 +# } +# ], +# "name": "pl_2" +# } +# ] +# }, +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_2_REMARK", +# "sequence": 3 +# }, +# { +# "action": "permit", +# "prefix": "10.0.0.0/24", +# "sequence": 4 +# } +# ], +# "name": "pl1" +# }, +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL2_REMARK", +# "sequence": 5 +# } +# ], +# "name": "pl2" +# } +# ] +# } +# ], +# "changed": true, +# "commands": [ +# "no ipv6 prefix-list pl_1", +# "no ipv6 prefix-list pl_2", +# "no ipv4 prefix-list pl1", +# "no ipv4 prefix-list pl2", +# "ipv4 prefix-list pl3 3 remark TEST_PL1_3_REMARK", +# "ipv4 prefix-list pl3 4 permit 10.0.0.0/24", +# "ipv4 prefix-list pl3 6 permit 35.0.0.0/8 eq 0" +# ], +# "invocation": { +# "module_args": { +# "config": [ +# { +# "afi": "ipv4", +# "prefix_lists": [ +# { +# "entries": [ +# { +# "action": "remark", +# "description": "TEST_PL1_3_REMARK", +# "prefix": null, +# "sequence": 3, +# "ge": null, +# "le": null, +# "eq": null +# }, +# { +# "action": "permit", +# "description": null, +# "prefix": "10.0.0.0/24", +# "sequence": 4, +# "ge": null, +# "le": null, +# "eq": null +# }, +# { +# "action": "permit", +# "description": null, +# "prefix": "35.0.0.0/8", +# "sequence": 6, +# "ge": null, +# "le": null, +# "eq": 0 +# } +# ], +# "name": "pl3" +# } +# ] +# } +# ], +# "running_config": null, +# "state": "overridden" +# } +# } +# } +# +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - "ipv6 prefix-list pl_1 1 deny 2001:db8:1234::/48" + - "ipv6 prefix-list pl_2 2 remark TEST_PL_2_REMARK" + - "ipv4 prefix-list pl1 3 remark TEST_PL1_2_REMARK" + - "ipv4 prefix-list pl1 4 permit 10.0.0.0/24" + - "ipv4 prefix-list pl2 5 remark TEST_PL2_REMARK" +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - "ipv6 prefix-list pl_1 1 deny 2001:db8:1234::/48" + - "ipv6 prefix-list pl_2 2 remark TEST_PL_2_REMARK" + - "ipv4 prefix-list pl1 3 remark TEST_PL1_2_REMARK" + - "ipv4 prefix-list pl1 4 permit 10.0.0.0/24" + - "ipv4 prefix-list pl2 5 remark TEST_PL2_REMARK" +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.prefix_lists.prefix_lists import ( + Prefix_listsArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.prefix_lists.prefix_lists import ( + Prefix_lists, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Prefix_listsArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Prefix_lists(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_snmp_server.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_snmp_server.py new file mode 100644 index 00000000..43d7016d --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_snmp_server.py @@ -0,0 +1,2328 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for iosxr_snmp_server +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: iosxr_snmp_server +short_description: Resource module to configure snmp server. +description: This module configures and manages the attributes of snmp-server on Cisco + IOSXR platforms. +version_added: 2.6.0 +author: Ashwini Mhatre (@amhatre) +notes: +- Tested against Cisco Iosxr 7.0.2 +- This module works with connection C(network_cli). +options: + config: + description: SNMP server configuration. + type: dict + suboptions: + chassis_id: + description: SNMP chassis identifier. + type: str + communities: + description: Enable SNMP; set community string and access privileges. + type: list + elements: dict + suboptions: + name: + description: Community name. + type: str + acl_v4: + description: Ipv4 access list. + type: str + acl_v6: + description: IPv6 access list name. + type: str + ro: + description: Only reads are permitted. + type: bool + rw: + description: Read-write access. + type: bool + sdrowner: + type: bool + description: SDR Owner permissions for MIB Objects. + systemowner: + type: bool + description: System Owner permissions for MIB objects. + v4_acl: + description: V4 Access-list name. + type: str + community_maps: + description: Community Mapping as per RFC-2576. + type: list + elements: dict + suboptions: + name: + description: Community name + type: str + context: + description: Context Name for the community mapping. + type: str + security_name: + description: Security Name for the community mapping. + type: str + target_list: + description: list of targets valid with this community. + type: str + correlator: + description: Configure properties of the event correlator + type: dict + suboptions: + buffer_size: + type: int + description: Configure size of the correlator buffer. + rules: + type: list + elements: dict + description: Configure a specified correlation rule. + suboptions: + rule_name: + type: str + description: name of rule. + timeout: + type: int + description: Specify timeout. + rule_sets: + type: list + elements: dict + description: Configure a specified correlation ruleset. + suboptions: + name: + type: str + description: Name of the ruleset + contact: + description: Person to contact about the syste,. + type: str + context: + description: Create/Delete a context apart from default + type: list + elements: str + drop: + type: dict + description: Silently drop SNMP packets + suboptions: + unknown_user: + description: Silently drop unknown v3 user packets + type: bool + report_IPv4: + description: Config to drop snmpv3 error reports matching Ipv4 ACL. + type: str + report_IPv6: + description: Config to drop snmpv3 error reports matching Ipv4 ACL. + type: str + engineid: + description: SNMPv3 engine ID configuration. + type: dict + suboptions: + local: + description: Local SNMP agent + type: str + groups: + description: SNMP USM group + type: list + elements: dict + suboptions: + group: + description: SNMP group for the user + type: str + version: + description: snmp security group version + type: str + choices: ['v1', 'v3', 'v2c'] + context: + description: Specify a context to associate with the group + type: str + notify: + description: View to restrict notifications + type: str + read: + description: View to restrict read access + type: str + write: + description: View to restrict write access + type: str + acl_v4: + description: Ipv4 Type of Access-list + type: str + aliases: + - Ipv4_acl + acl_v6: + description: Ipv6 Type of Access-list + type: str + aliases: + - Ipv6_acl + v4_acl: + description: V4 Access-list name + type: str + hosts: &hosts + description: Notification destinations + type: list + elements: dict + suboptions: + host: + description: Hostname or IP address of SNMP notification host. + type: str + community: + description: community string. + type: str + udp_port: + description: UDP destination port for notification messages. + type: int + informs: + description: Use SNMP inform messages. + type: bool + traps: + description: Use SNMP trap messages + type: bool + version: + description: Notification message SNMP version. + type: str + choices: ['1', '2c', '3'] + ifindex: + description: Enable ifindex persistence + type: bool + ifmib: + type: dict + description: IF-MIB configuration commands. + suboptions: + ifalias_long: + type: bool + description: Modify parameters for ifAlias object. + internal_cache_max_duration: + type: int + description: IFMIB internal lookahead cache. + ipsubscriber: + type: bool + description: Enable ipsubscriber interfaces in IFMIB. + stats: + type: bool + description: Modify IF-MIB statistics parameters. + inform: + description: Configure SNMP Informs options + suboptions: + pending: + description: Set number of unacked informs to hold + type: int + retries: + description: Set retry count for informs + type: int + timeout: + description: Set timeout for informs + type: int + type: dict + interfaces: + type: list + elements: dict + description: Enter the SNMP interface configuration commands. + suboptions: + name: + type: str + description: Name of interface. + notification_linkupdown_disable: + type: bool + description: Disable linkUp and linkDown notification. + index_persistent: + type: bool + description: Configure ifIndex attributes Persistency across system reloads. + ipv4: &ip + description: Mark the dscp/precedence bit for ipv4 packets. + type: dict + suboptions: + dscp: + description: Set IP DSCP (DiffServ CodePoint).Please refer vendor document for valid entries. + type: str + precedence: + description: Set precedence Please refer vendor document for valid entries. + type: str + ipv6: *ip + location: + description: The sysLocation string. + type: str + logging_threshold_oid_processing: + type: int + description: Configure threshold to start logging slow OID requests processing. + logging_threshold_pdu_processing: + type: int + description: Configure threshold to start logging slow PDU requests processing. + mib_bulkstat_max_procmem_size: + type: int + description: per process memory limit in kilo bytes + mib_object_lists: + description: mib object lists + type: list + elements: str + mib_schema: + type: list + elements: dict + description: mib schema + suboptions: + name: + type: str + description: mib schema name. + object_list: + type: str + description: Name of an object List. + poll_interval: + type: int + description: Periodicity for polling of objects in this schema in Min. + mib_bulkstat_transfer_ids: + description: mib bulkstat transfer ids. + type: list + elements: dict + suboptions: + name: + type: str + description: mib transfer-id name. + buffer_size: + type: int + description: Bulkstat data file maximum size. + enable: + type: bool + description: Start Data Collection for this Configuration + format_schemaASCI: + type: bool + description: format + retain: + type: int + description: Retention period in Min. + retry: + type: int + description: Number of Retries. + schema: + type: str + description: Schema that contains objects to be collected. + transfer_interval: + type: int + description: transfer-interval + mroutemib_send_all_vrf: + type: bool + description: Configurations related to IPMROUTE-MIB(cisco-support). + notification_log_mib: + description: notification log mib. + type: dict + suboptions: + GlobalSize: + type: int + description: GlobalSize, max number of notifications that can be logged in all logs. + default: + type: bool + description: To create a default log + disable: + type: bool + description: disable, to disable the logging in default log. + size: + description: size, The max number of notifications that this log (default) can hold. + type: int + oid_poll_stats: + type: bool + description: Enable OID poll stats oper CLI + overload_control: + type: dict + description: Set overload-control params for handling incoming messages in critical processing mode. + suboptions: + overload_drop_time: + type: int + description: Overload drop time (in seconds) for incoming queue (default 1 sec). + overload_throttle_rate: + type: int + description: Overload throttle rate for incoming queue (default 500 msec) + packetsize: + type: int + description: Largest SNMP packet size. + queue_length: + type: int + description: Queue length (default 100). + targets: + type: list + elements: dict + description: targets + suboptions: + name: + type: str + description: Name of the target list. + host: + type: str + description: Specify host name. + vrf: + type: str + description: Specify VRF name. + throttle_time: + type: int + description: Set throttle time for handling incoming messages. + timeouts: + type: dict + description: SNMP timeouts + suboptions: + duplicate: + description: Duplicate request feature timeout + type: int + inQdrop: + type: int + description: incoming queue drop feature. + pdu_stats: + type: int + description: SNMP pdu statistics end to end. + subagent: + type: int + description: Sub-Agent Request timeout. + threshold: + type: int + description: threshold incoming queue drop feature. + trap: + type: dict + description: MIB trap configurations. + suboptions: + authentication_vrf_disable: + type: bool + description: Disable authentication traps for packets on a vrf. + link_ietf: + type: bool + description: Link up/down trap configuratio. + throttle_time: + type: int + description: Set throttle time for handling more traps. + trap_source: + description: Assign an interface for the source address of all traps + type: str + trap_timeout: + description: Set timeout for TRAP message retransmissions + type: int + traps: + description: Enable traps to all configured recipients. + type: dict + suboptions: + addrpool: + type: dict + description: Enable SNMP Address Pool traps. + suboptions: + low: + type: bool + description: Enable SNMP Address Pool Low Threshold trap. + high: + type: bool + description: Enable SNMP Address Pool High Threshold trap. + bfd: + type: bool + description: Enable BFD traps. + bgp: + description: Enable Bgp traps. + type: dict + suboptions: + cbgp2: + type: bool + description: Enable CISCO-BGP4-MIB v2 traps. + updown: + type: bool + description: Enable CISCO-BGP4-MIB v2 up/down traps. + bulkstat_collection: + type: bool + description: Enable Data-Collection-MIB Collection notifications. + bulkstat_transfer: + type: bool + description: Enable Data-Collection-MIB Trnasfer notifications. + bridgemib: + type: bool + description: Enable SNMP Trap for Bridge MIB. + copy_complete: + type: bool + description: Enable CISCO-CONFIG-COPY-MIB ccCopyCompletion traps. + cisco_entity_ext: + type: bool + description: Enable SNMP entity traps + config: + type: bool + description: Enable SNMP config traps. + diameter: + type: dict + description: Enable SNMP diameter traps. + suboptions: + peerdown: + type: bool + description: Enable peer connection down notification. + peerup: + type: bool + description: Enable peer connection up notification. + permanentfail: + type: bool + description: Enable permanent failure notification. + protocolerror: + type: bool + description: Enable protocol error notifications + transientfail: + type: bool + description: Enable transient failure notification. + entity: + type: bool + description: Enable SNMP entity traps. + entity_redundancy: + type: dict + description: Enable SNMP CISCO-ENTITY-REDUNDANCY-MIB traps. + suboptions: + all: + type: bool + description: Enable all CISCO-ENTITY-REDUNDANCY-MIB traps + status: + type: bool + description: Enable status change traps + switchover: + type: bool + description: Enable switchover traps. + entity_state: + type: dict + description: Enable SNMP entity-state traps. + suboptions: + operstatus: + type: bool + description: Enable entity oper status enable notification. + switchover: + description: Enable entity state switchover notifications + type: bool + flash: + type: dict + description: Enable flash-mib traps. + suboptions: + insertion: + type: bool + description: Enable ciscoFlashDeviceInsertedNotif. + removal: + type: bool + description: Enable ciscoFlashDeviceRemovedNotif. + fru_ctrl: + type: bool + description: Enable SNMP entity FRU control traps. + hsrp: + type: bool + description: Enable SNMP hsrp traps. + ipsla: + type: bool + description: Enable SNMP hipsla traps. + ipsec: + type: dict + description: Enable SNMP IPSec traps. + suboptions: + start: + type: bool + description: Enable SNMP IPsec Tunnel Start trap. + stop: + type: bool + description: Enable SNMP IPsec Tunnel Stop trap. + isakmp: + type: dict + description: Enable SNMP isakmp traps. + suboptions: + start: + type: bool + description: Enable SNMP isakmp Tunnel Start trap. + stop: + type: bool + description: Enable SNMP isakmp Tunnel Stop trap. + + isis: + description: Enable isis traps. If set to enabled , all the traps are set. + type: dict + suboptions: + adjacency_change: + description: adjacency-change + type: bool + all: + type: bool + description: anable all is-is traps. + area_mismatch: + description: area-mismatch + type: bool + attempt_to_exceed_max_sequence: + description: attempt-to-exceed-max-sequence + type: bool + authentication_failure: + description: authentication-failure. + type: bool + authentication_type_failure: + description: authentication-type-failure. + type: bool + corrupted_lsp_detected: + description: isisCorruptedLSPDetected + type: bool + database_overload: + description: database-overload + type: bool + id_len_mismatch: + type: bool + description: isisIDLenMismatch + lsp_error_detected: + type: bool + description: lsp-error-detected. + lsp_too_large_to_propagate: + type: bool + description: lsp-too-large-to-propagate + manual_address_drops: + type: bool + description: manual_address_drops + max_area_addresses_mismatch: + type: bool + description: max_area_addresses_mismatch + orig_lsp_buff_size_mismatch: + type: bool + description: orig-lsp-buff-size-mismatch + version_skew: + type: bool + description: version-skew + own_lsp_purge: + description: own-lsp-purge + type: bool + rejected_adjacency: + description: rejected-adjacency + type: bool + protocols_supported_mismatch: + description: protocols-supported-mismatch + type: bool + sequence_number_skip: + description: sequence-number-skip. + type: bool + l2tun: + type: dict + description: Enable L2TUN traps. + suboptions: + pseudowire_status: + type: bool + description: Enable L2TUN pseudowire status traps. + sessions: + type: bool + description: Enable L2TUN sessions traps. + tunnel_down: + type: bool + description: Enable L2TUN tunnel DOWN traps. + tunnel_up: + type: bool + description: Enable L2TUN tunnel UP traps. + l2vpn: + type: dict + description: Enable L2VPN traps. + suboptions: + all: + type: bool + description: Enable L2VPN ALL traps. + cisco: + type: bool + description: Enable L2VPN CISCO traps. + vc_down: + type: bool + description: Enable L2VPN VC DOWN traps. + vc_up: + type: bool + description: Enable L2VPN VC UP traps. + msdp_peer_state_change: + type: bool + description: Enable SNMP MSDP traps + ntp: + type: bool + description: Enable SNMP Cisco Ntp traps. + ospf: + description: Enable Ospf traps. If set to enabled , all the traps are set. + type: dict + suboptions: + errors: + description: error + type: dict + suboptions: + bad_packet: + type: bool + description: bad-packet + authentication_failure: + type: bool + description: authentication-failure. + config_error: + type: bool + description: config-error + virt_bad_packet: + type: bool + description: virt-bad-packet + virt_authentication_failure: + type: bool + description: virt-authentication-failure + virt_config_error: + type: bool + description: virt_config_error + lsa: + description: lsa + type: dict + suboptions: + lsa_maxage: + type: bool + description: lsa-maxage + lsa_originate: + type: bool + description: lsa-originate + retransmit: + description: retransmit + type: dict + suboptions: + packets: + type: bool + description: packets + virt_packets: + type: bool + description: virt-packets + state_change: + description: state-change. + type: dict + suboptions: + if_state_change: + type: bool + description: if-state-change + neighbor_state_change: + type: bool + description: neighbor-state-change + virtif_state_change: + type: bool + description: virtif-state-change + virtneighbor_state_change: + type: bool + description: virtneighbor-state-change + ospfv3: + description: Enable Ospfv3 traps. If set to enabled , all the traps are set. + type: dict + suboptions: + errors: + description: error + type: dict + suboptions: + bad_packet: + type: bool + description: bad-packet + config_error: + type: bool + description: config-error + virt_bad_packet: + type: bool + description: virt-bad-packet + virt_config_error: + type: bool + description: virt_config_error + state_change: + description: state-change. + type: dict + suboptions: + if_state_change: + type: bool + description: if-state-change + neighbor_state_change: + type: bool + description: neighbor-state-change + virtif_state_change: + type: bool + description: virtif-state-change + virtneighbor_state_change: + type: bool + description: virtneighbor-state-change + nssa_state_change: + type: bool + description: nssa-state-change + restart_status_change: + type: bool + description: restart-status-change + restart_helper_status_change: + type: bool + description: restart-helper-status-change + restart_virtual_helper_status_change: + type: bool + description: restart-virtual-helper-status-change + power: + type: bool + description: Enable SNMP entity power traps. + rf: + type: bool + description: Enable SNMP RF-MIB traps. + pim: + description: Enable Pim traps. If set to enabled , all the traps are set. + type: dict + suboptions: + interface_state_change : + description: interface-state-change . + type: bool + invalid_message_received : + description: invalid-message-received + type: bool + neighbor_change: + description: neighbor-change. + type: bool + rp_mapping_change: + description: rp-mapping-change. + type: bool + rsvp: + description: Enable rsvp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + all: + description: enable all traps. + type: bool + lost_flow: + description: lost-flow + type: bool + new_flow: + description: new-flow + type: bool + selective_vrf_download_role_change: + type: bool + description: Enable selective VRF download traps. + sensor: + type: bool + description: Enable SNMP entity sensor traps + snmp: + description: Enable snmp traps. If set to enabled , all the traps are set. + type: dict + suboptions: + authentication: + description: authentication + type: bool + linkdown: + description: link-down + type: bool + linkup: + description: link-up + type: bool + warmstart: + description: warmstart. + type: bool + coldstart: + description: coldstart. + type: bool + vrrp_events: + description: vrrp + type: bool + syslog: + type: bool + description: syslog + subscriber: + type: dict + description: Subscriber notification commands. + suboptions: + session_agg_access_interface: + type: bool + description: Subscriber notification at access interface level + session_agg_node: + type: bool + description: Subscriber notification at node level + system: + type: bool + description: Enable SNMP SYSTEMMIB-MIB traps. + vpls: + type: dict + description: Enable VPLS traps + suboptions: + all: + type: bool + description: Enable all VPLS traps. + full_clear: + type: bool + description: Enable VPLS Full Clear traps. + full_raise: + type: bool + description: Enable VPLS Full Raise traps. + status: + type: bool + description: Enable VPLS Status traps + users: + description: SNMP user configuration. + type: list + elements: dict + suboptions: + user: + description: SNMP user name + type: str + group: + description: SNMP group for the user. + type: str + acl_v4: + description: Ipv4 Type of Access-list + type: str + aliases: + - Ipv4_acl + acl_v6: + description: Ipv6 Type of Access-list + type: str + aliases: + - Ipv6_acl + SDROwner: + description: SDR Owner permissions for MIB Objects. + type: bool + SystemOwner: + description: System Owner permissions for MIB objects. + type: bool + v4_acl: + type: str + description: V4 Access-list name + version: + description: snmp security version + type: str + choices: ['v1', 'v2c', 'v3'] + vrfs: + description: Specify the VRF in which the source address is used + type: list + elements: dict + suboptions: + vrf: + description: vrf name. + type: str + context: + description: Configure the source interface for SNMP notifications + type: list + elements: str + hosts: *hosts + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOSXR device by + executing the command B(show running-config snmp-server). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + description: + - The state the configuration should be left in. + - The states I(replaced) and I(overridden) have identical + behaviour for this module. + - Please refer to examples for more details. + type: str + choices: [deleted, merged, overridden, replaced, gathered, rendered, parsed] + default: merged +""" + +EXAMPLES = """ +# Using state: merged +# Before state: +# ------------- +# RP/0/RP0/CPU0:test2#show running-config snmp-server +# --------------------- EMPTY ----------------- +# Merged play: +# ------------ +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_snmp_server: + config: + vrfs: + - hosts: + - community: test1 + host: 1.1.1.1 + traps: true + vrf: vrf1 + users: + - Ipv4_acl: test1 + Ipv6_acl: test2 + group: test2 + user: u1 + version: v1 + timeouts: + duplicate: 0 + inQdrop: 0 + trap: + throttle_time: 12 + targets: + - host: 1.1.1.2 + name: test + + ifmib: + internal_cache_max_duration: 4 + inform: + retries: 7 + chassis_id: test2 + packetsize: 490 + queue_length: 2 + throttle_time: 60 + trap_source: GigabitEthernet0/0/0/2 + trap_timeout: 3 + context: + - c1 + - c2 + contact: t1 + correlator: + buffer_size: 1024 + communities: + - name: test2 + ro: true + sdrowner: true + acl_v4: test + acl_v6: test1 + community_maps: + - name: cm1 + context: c1 + target_list: t1 + security_name: s1 + drop: + report_IPv4: test1 + unknown_user: true + ipv6: + precedence: routine + ipv4: + dscp: af11 + location: test1 + logging_threshold_oid_processing: 1 + logging_threshold_pdu_processing: 1 + mib_bulkstat_max_procmem_size: 101 + mroutemib_send_all_vrf: true + overload_control: + overload_drop_time: 4 + overload_throttle_rate: 6 + notification_log_mib: + GlobalSize: 5 + size: 5 + traps: + hsrp: true + ipsla: true + ipsec: + start: true + stop: true + bridgemib: true + bulkstat_collection: true + cisco_entity_ext: true + config: true + copy_complete: true + addrpool: + high: true + low: true + bfd: true + bgp: + cbgp2: true + l2tun: + sessions: true + tunnel_down: true + tunnel_up: true + l2vpn: + all: true + vc_down: true + vc_up: true + msdp_peer_state_change: true +# +# Commands Fired: +# ------------ +# "commands": [ +# "snmp-server chassis-id test2", +# "snmp-server correlator buffer-size 1024", +# "snmp-server contact t1", +# "snmp-server ipv4 dscp af11", +# "snmp-server ipv6 precedence routine", +# "snmp-server location test1", +# "snmp-server logging threshold oid-processing 1", +# "snmp-server logging threshold pdu-processing 1", +# "snmp-server mib bulkstat max-procmem-size 101", +# "snmp-server mroutemib send-all-vrf", +# "snmp-server overload-control 4 6", +# "snmp-server packetsize 490", +# "snmp-server queue-length 2", +# "snmp-server throttle-time 60", +# "snmp-server trap-source GigabitEthernet0/0/0/2", +# "snmp-server trap-timeout 3", +# "snmp-server drop report acl IPv4 test1", +# "snmp-server drop unknown-user", +# "snmp-server ifmib internal cache max-duration 4", +# "snmp-server inform retries 7", +# "snmp-server notification-log-mib size 5", +# "snmp-server notification-log-mib GlobalSize 5", +# "snmp-server trap throttle-time 12", +# "snmp-server timeouts inQdrop 0", +# "snmp-server timeouts duplicate 0", +# "snmp-server traps addrpool low", +# "snmp-server traps addrpool high", +# "snmp-server traps bfd", +# "snmp-server traps bgp cbgp2", +# "snmp-server traps bulkstat collection", +# "snmp-server traps bridgemib", +# "snmp-server traps copy-complete", +# "snmp-server traps cisco-entity-ext", +# "snmp-server traps config", +# "snmp-server traps hsrp", +# "snmp-server traps ipsla", +# "snmp-server traps ipsec tunnel start", +# "snmp-server traps ipsec tunnel stop", +# "snmp-server traps l2tun sessions", +# "snmp-server traps l2tun tunnel-up", +# "snmp-server traps l2tun tunnel-down", +# "snmp-server traps l2vpn all", +# "snmp-server traps l2vpn vc-up", +# "snmp-server traps l2vpn vc-down", +# "snmp-server traps msdp peer-state-change", +# "snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", +# "snmp-server community-map cm1 context c1 security-name s1 target-list t1", +# "snmp-server context c1", +# "snmp-server context c2", +# "snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2", +# "snmp-server target list test2 vrf vrf2", +# "snmp-server target list test host 1.1.1.2", +# "snmp-server vrf vrf1", +# "host 1.1.1.1 traps test1" +# +# ], +# After state: +# ------------ +# RP/0/RP0/CPU0:test2#show running-config snmp-server +# Mon Nov 29 12:49:29.521 UTC +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# +# +# Using state: deleted +# Before state: +# ------------- +# RP/0/RP0/CPU0:test2#show running-config snmp-server +# Mon Nov 29 12:49:29.521 UTC +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# Deleted play: +# ------------- +- name: Remove all existing configuration + cisco.iosxr.iosxr_snmp_server: + state: deleted +# Commands Fired: +# --------------- +# "commands": [ +# "no snmp-server chassis-id test2", +# "no snmp-server correlator buffer-size 1024", +# "no snmp-server contact t1", +# "no snmp-server ipv4 dscp af11", +# "no snmp-server ipv6 precedence routine", +# "no snmp-server location test1", +# "no snmp-server logging threshold oid-processing 1", +# "no snmp-server logging threshold pdu-processing 1", +# "no snmp-server mib bulkstat max-procmem-size 101", +# "no snmp-server mroutemib send-all-vrf", +# "no snmp-server overload-control 4 6", +# "no snmp-server packetsize 490", +# "no snmp-server queue-length 2", +# "no snmp-server throttle-time 60", +# "no snmp-server trap-source GigabitEthernet0/0/0/2", +# "no snmp-server trap-timeout 3", +# "no snmp-server drop report acl IPv4 test1", +# "no snmp-server drop unknown-user", +# "no snmp-server ifmib internal cache max-duration 4", +# "no snmp-server inform retries 7", +# "no snmp-server notification-log-mib size 5", +# "no snmp-server notification-log-mib GlobalSize 5", +# "no snmp-server trap throttle-time 12", +# "no snmp-server timeouts inQdrop 0", +# "no snmp-server timeouts duplicate 0", +# "no snmp-server traps addrpool low", +# "no snmp-server traps addrpool high", +# "no snmp-server traps bfd", +# "no snmp-server traps bgp cbgp2", +# "no snmp-server traps bulkstat collection", +# "no snmp-server traps bridgemib", +# "no snmp-server traps copy-complete", +# "no snmp-server traps cisco-entity-ext", +# "no snmp-server traps config", +# "no snmp-server traps hsrp", +# "no snmp-server traps ipsla", +# "no snmp-server traps ipsec tunnel start", +# "no snmp-server traps ipsec tunnel stop", +# "no snmp-server traps l2tun sessions", +# "no snmp-server traps l2tun tunnel-up", +# "no snmp-server traps l2tun tunnel-down", +# "no snmp-server traps l2vpn all", +# "no snmp-server traps l2vpn vc-up", +# "no snmp-server traps l2vpn vc-down", +# "no snmp-server traps msdp peer-state-change", +# "no snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", +# "no snmp-server community-map cm1 context c1 security-name s1 target-list t1", +# "no snmp-server context c1", +# "no snmp-server context c2", +# "no snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2", +# "no snmp-server target list test host 1.1.1.2", +# "no snmp-server target list test2 vrf vrf2", +# "no snmp-server vrf vrf1" +# ], +# After state: +# ------------ +# RP/0/0/CPU0:10#show running-config ntp +# --------------------- EMPTY ----------------- +# Using state: overridden +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config snmp-server +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# Overridden play: +# ---------------- +- name: Override Snmp-server configuration with provided configuration + cisco.iosxr.iosxr_snmp_server: + config: + timeouts: + duplicate: 0 + inQdrop: 0 + trap: + throttle_time: 13 + targets: + - host: 1.1.1.2 + name: test + + ifmib: + internal_cache_max_duration: 5 + inform: + retries: 7 + chassis_id: test + packetsize: 491 + queue_length: 2 + throttle_time: 60 + trap_source: GigabitEthernet0/0/0/2 + trap_timeout: 3 + context: + - c1 + - c2 + contact: t1 + correlator: + buffer_size: 1025 + communities: + - name: test1 + ro: true + sdrowner: true + acl_v4: test + acl_v6: test1 + community_maps: + - name: cm2 + context: c1 + target_list: t1 + security_name: s1 + drop: + report_IPv4: test2 + unknown_user: true + ipv6: + precedence: routine + ipv4: + dscp: af11 + location: test1 + logging_threshold_oid_processing: 2 + logging_threshold_pdu_processing: 2 + mib_bulkstat_max_procmem_size: 101 + mroutemib_send_all_vrf: true + overload_control: + overload_drop_time: 4 + overload_throttle_rate: 6 + notification_log_mib: + GlobalSize: 5 + size: 5 + traps: + hsrp: true + ipsla: true + ipsec: + start: true + stop: true + bridgemib: true + bulkstat_collection: true + cisco_entity_ext: true + config: true + copy_complete: true + l2vpn: + all: true + vc_down: true + vc_up: true + msdp_peer_state_change: true + state: overridden +# Commands Fired: +# --------------- +# "commands": [ +# "no snmp-server traps addrpool low", +# "no snmp-server traps addrpool high", +# "no snmp-server traps bfd", +# "no snmp-server traps bgp cbgp2", +# "no snmp-server traps l2tun sessions", +# "no snmp-server traps l2tun tunnel-up", +# "no snmp-server traps l2tun tunnel-down", +# "no snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", +# "no snmp-server community-map cm1 context c1 security-name s1 target-list t1", +# "no snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2", +# "no snmp-server vrf vrf1", +# "snmp-server chassis-id test", +# "snmp-server correlator buffer-size 1025", +# "snmp-server logging threshold oid-processing 2", +# "snmp-server logging threshold pdu-processing 2", +# "snmp-server packetsize 491", +# "snmp-server drop report acl IPv4 test2", +# "snmp-server ifmib internal cache max-duration 5", +# "snmp-server trap throttle-time 13", +# "snmp-server community test1 RO SDROwner IPv4 test IPv6 test1", +# "snmp-server community-map cm2 context c1 security-name s1 target-list t1" +# ], +# After state: +# ------------ +# RP/0/RP0/CPU0:test2#show running-config snmp-server +# Mon Nov 29 12:57:34.182 UTC +# snmp-server drop report acl IPv4 test2 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server community test1 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 13 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 2 +# snmp-server logging threshold pdu-processing 2 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 491 +# snmp-server correlator buffer-size 1025 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm2 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 5 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# +# Using state: replaced +# Before state: +# ------------- +# RP/0/0/CPU0:10#show running-config snmp-server +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# +# +# Replaced play: +# ---------------- +- name: Replace Snmp-server configuration with provided configuration + cisco.iosxr.iosxr_snmp_server: + state: replaced + config: + timeouts: + duplicate: 0 + inQdrop: 0 + trap: + throttle_time: 13 + targets: + - host: 1.1.1.2 + name: test + + ifmib: + internal_cache_max_duration: 5 + inform: + retries: 7 + chassis_id: test + packetsize: 491 + queue_length: 2 + throttle_time: 60 + trap_source: GigabitEthernet0/0/0/2 + trap_timeout: 3 + context: + - c1 + - c2 + contact: t1 + correlator: + buffer_size: 1025 + communities: + - name: test1 + ro: true + sdrowner: true + acl_v4: test + acl_v6: test1 + community_maps: + - name: cm2 + context: c1 + target_list: t1 + security_name: s1 + drop: + report_IPv4: test2 + unknown_user: true + ipv6: + precedence: routine + ipv4: + dscp: af11 + location: test1 + logging_threshold_oid_processing: 2 + logging_threshold_pdu_processing: 2 + mib_bulkstat_max_procmem_size: 101 + mroutemib_send_all_vrf: true + overload_control: + overload_drop_time: 4 + overload_throttle_rate: 6 + notification_log_mib: + GlobalSize: 5 + size: 5 + traps: + hsrp: true + ipsla: true + ipsec: + start: true + stop: true + bridgemib: true + bulkstat_collection: true + cisco_entity_ext: true + config: true + copy_complete: true + l2vpn: + all: true + vc_down: true + vc_up: true + msdp_peer_state_change: true +# +# Commands Fired: +# --------------- +# "commands": [ +# "no snmp-server traps addrpool low", +# "no snmp-server traps addrpool high", +# "no snmp-server traps bfd", +# "no snmp-server traps bgp cbgp2", +# "no snmp-server traps l2tun sessions", +# "no snmp-server traps l2tun tunnel-up", +# "no snmp-server traps l2tun tunnel-down", +# "no snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", +# "no snmp-server community-map cm1 context c1 security-name s1 target-list t1", +# "no snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2", +# "no snmp-server vrf vrf1", +# "snmp-server chassis-id test", +# "snmp-server correlator buffer-size 1025", +# "snmp-server logging threshold oid-processing 2", +# "snmp-server logging threshold pdu-processing 2", +# "snmp-server packetsize 491", +# "snmp-server drop report acl IPv4 test2", +# "snmp-server ifmib internal cache max-duration 5", +# "snmp-server trap throttle-time 13", +# "snmp-server community test1 RO SDROwner IPv4 test IPv6 test1", +# "snmp-server community-map cm2 context c1 security-name s1 target-list t1" +# ], +# After state: +# ------------ +# RP/0/RP0/CPU0:ios#show running-config snmp-server +# Mon Sep 13 10:38:22.690 UTC +# RP/0/0/CPU0:10#show running-config snmp-server +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# +# +# Using state: gathered +# Before state: +# ------------- +# RP/0/RP0/CPU0:test2#show running-config snmp-server +# Mon Nov 29 12:49:29.521 UTC +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# Gathered play: +# -------------- +- name: Gather listed snmp server + cisco.iosxr.iosxr_snmp_server: + state: gathered +# Module Execution Result: +# ------------------------ +# "gathered": { +# "chassis_id": "test2", +# "communities": [ +# { +# "acl_v4": "test", +# "acl_v6": "test1", +# "name": "test2", +# "ro": true, +# "sdrowner": true +# } +# ], +# "community_maps": [ +# { +# "context": "c1", +# "name": "cm1", +# "security_name": "s1", +# "target_list": "t1" +# } +# ], +# "contact": "t1", +# "context": [ +# "c1", +# "c2" +# ], +# "correlator": { +# "buffer_size": 1024 +# }, +# "drop": { +# "report_IPv4": "test1", +# "unknown_user": true +# }, +# "ifmib": { +# "internal_cache_max_duration": 4 +# }, +# "inform": { +# "retries": 7 +# }, +# "ipv4": { +# "dscp": "af11" +# }, +# "ipv6": { +# "precedence": "routine" +# }, +# "location": "test1", +# "logging_threshold_oid_processing": 1, +# "logging_threshold_pdu_processing": 1, +# "mib_bulkstat_max_procmem_size": 101, +# "mroutemib_send_all_vrf": true, +# "notification_log_mib": { +# "GlobalSize": 5, +# "size": 5 +# }, +# "overload_control": { +# "overload_drop_time": 4, +# "overload_throttle_rate": 6 +# }, +# "packetsize": 490, +# "queue_length": 2, +# "targets": [ +# { +# "host": "1.1.1.2", +# "name": "test" +# }, +# { +# "name": "test2", +# "vrf": "vrf2" +# } +# ], +# "throttle_time": 60, +# "timeouts": { +# "duplicate": 0, +# "inQdrop": 0 +# }, +# "trap": { +# "throttle_time": 12 +# }, +# "trap_source": "GigabitEthernet0/0/0/2", +# "trap_timeout": 3, +# "traps": { +# "addrpool": { +# "high": true, +# "low": true +# }, +# "bfd": true, +# "bgp": { +# "cbgp2": true +# }, +# "bridgemib": true, +# "bulkstat_collection": true, +# "cisco_entity_ext": true, +# "config": true, +# "copy_complete": true, +# "hsrp": true, +# "ipsec": { +# "start": true, +# "stop": true +# }, +# "ipsla": true, +# "l2tun": { +# "sessions": true, +# "tunnel_down": true, +# "tunnel_up": true +# }, +# "l2vpn": { +# "all": true, +# "vc_down": true, +# "vc_up": true +# }, +# "msdp_peer_state_change": true +# }, +# "users": [ +# { +# "Ipv4_acl": "test1", +# "Ipv6_acl": "test2", +# "group": "test2", +# "user": "u1", +# "version": "v1" +# } +# ], +# "vrfs": [ +# { +# "hosts": [ +# { +# "community": "test1", +# "host": "1.1.1.1", +# "traps": true +# } +# ], +# "vrf": "vrf1" +# } +# ] +# } +# +# +# Using state: rendered +# Rendered play: +# -------------- +- name: Render platform specific configuration lines with state rendered (without connecting to the device) + cisco.iosxr.iosxr_snmp_server: + state: rendered + config: + vrfs: + - hosts: + - community: test1 + host: 1.1.1.1 + traps: true + vrf: vrf1 + users: + - Ipv4_acl: test1 + Ipv6_acl: test2 + group: test2 + user: u1 + version: v1 + timeouts: + duplicate: 0 + inQdrop: 0 + trap: + throttle_time: 12 + targets: + - host: 1.1.1.2 + name: test + + ifmib: + internal_cache_max_duration: 4 + inform: + retries: 7 + chassis_id: test2 + packetsize: 490 + queue_length: 2 + throttle_time: 60 + trap_source: GigabitEthernet0/0/0/2 + trap_timeout: 3 + context: + - c1 + - c2 + contact: t1 + correlator: + buffer_size: 1024 + communities: + - name: test2 + ro: true + sdrowner: true + acl_v4: test + acl_v6: test1 + community_maps: + - name: cm1 + context: c1 + target_list: t1 + security_name: s1 + drop: + report_IPv4: test1 + unknown_user: true + ipv6: + precedence: routine + ipv4: + dscp: af11 + location: test1 + logging_threshold_oid_processing: 1 + logging_threshold_pdu_processing: 1 + mib_bulkstat_max_procmem_size: 101 + mroutemib_send_all_vrf: true + overload_control: + overload_drop_time: 4 + overload_throttle_rate: 6 + notification_log_mib: + GlobalSize: 5 + size: 5 + traps: + hsrp: true + ipsla: true + ipsec: + start: true + stop: true + bridgemib: true + bulkstat_collection: true + cisco_entity_ext: true + config: true + copy_complete: true + addrpool: + high: true + low: true + bfd: true + bgp: + cbgp2: true + l2tun: + sessions: true + tunnel_down: true + tunnel_up: true + l2vpn: + all: true + vc_down: true + vc_up: true + msdp_peer_state_change: true + register: result +# Module Execution Result: +# ------------------------ +# "rendered": [ +# "snmp-server chassis-id test2", +# "snmp-server correlator buffer-size 1024", +# "snmp-server contact t1", +# "snmp-server ipv4 dscp af11", +# "snmp-server ipv6 precedence routine", +# "snmp-server location test1", +# "snmp-server logging threshold oid-processing 1", +# "snmp-server logging threshold pdu-processing 1", +# "snmp-server mib bulkstat max-procmem-size 101", +# "snmp-server mroutemib send-all-vrf", +# "snmp-server overload-control 4 6", +# "snmp-server packetsize 490", +# "snmp-server queue-length 2", +# "snmp-server throttle-time 60", +# "snmp-server trap-source GigabitEthernet0/0/0/2", +# "snmp-server trap-timeout 3", +# "snmp-server drop report acl IPv4 test1", +# "snmp-server drop unknown-user", +# "snmp-server ifmib internal cache max-duration 4", +# "snmp-server inform retries 7", +# "snmp-server notification-log-mib size 5", +# "snmp-server notification-log-mib GlobalSize 5", +# "snmp-server trap throttle-time 12", +# "snmp-server timeouts inQdrop 0", +# "snmp-server timeouts duplicate 0", +# "snmp-server traps addrpool low", +# "snmp-server traps addrpool high", +# "snmp-server traps bfd", +# "snmp-server traps bgp cbgp2", +# "snmp-server traps bulkstat collection", +# "snmp-server traps bridgemib", +# "snmp-server traps copy-complete", +# "snmp-server traps cisco-entity-ext", +# "snmp-server traps config", +# "snmp-server traps hsrp", +# "snmp-server traps ipsla", +# "snmp-server traps ipsec tunnel start", +# "snmp-server traps ipsec tunnel stop", +# "snmp-server traps l2tun sessions", +# "snmp-server traps l2tun tunnel-up", +# "snmp-server traps l2tun tunnel-down", +# "snmp-server traps l2vpn all", +# "snmp-server traps l2vpn vc-up", +# "snmp-server traps l2vpn vc-down", +# "snmp-server traps msdp peer-state-change", +# "snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", +# "snmp-server community-map cm1 context c1 security-name s1 target-list t1", +# "snmp-server context c1", +# "snmp-server context c2", +# "snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2", +# "snmp-server target list test2 vrf vrf2", +# "snmp-server target list test host 1.1.1.2", +# "snmp-server vrf vrf1", +# "host 1.1.1.1 traps test1" +# ], +# Using state: parsed +# File: parsed.cfg +# ---------------- +# snmp-server vrf vrf1 +# host 1.1.1.1 traps test1 +# ! +# snmp-server drop report acl IPv4 test1 +# snmp-server drop unknown-user +# snmp-server ipv4 dscp af11 +# snmp-server ipv6 precedence routine +# snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 +# snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 +# snmp-server queue-length 2 +# snmp-server trap-timeout 3 +# snmp-server trap throttle-time 12 +# snmp-server traps bfd +# snmp-server traps bgp cbgp2 +# snmp-server traps copy-complete +# snmp-server traps hsrp +# snmp-server traps ipsla +# snmp-server traps msdp peer-state-change +# snmp-server traps ipsec tunnel stop +# snmp-server traps ipsec tunnel start +# snmp-server traps config +# snmp-server traps l2tun sessions +# snmp-server traps l2tun tunnel-up +# snmp-server traps l2tun tunnel-down +# snmp-server traps bulkstat collection +# snmp-server traps l2vpn all +# snmp-server traps l2vpn vc-up +# snmp-server traps l2vpn vc-down +# snmp-server traps bridgemib +# snmp-server traps addrpool low +# snmp-server traps addrpool high +# snmp-server traps cisco-entity-ext +# snmp-server chassis-id test2 +# snmp-server contact t1 +# snmp-server location test1 +# snmp-server target list test host 1.1.1.2 +# snmp-server target list test2 vrf vrf2 +# snmp-server context c1 +# snmp-server context c2 +# snmp-server logging threshold oid-processing 1 +# snmp-server logging threshold pdu-processing 1 +# snmp-server mib bulkstat max-procmem-size 101 +# snmp-server timeouts duplicate 0 +# snmp-server timeouts inQdrop 0 +# snmp-server packetsize 490 +# snmp-server correlator buffer-size 1024 +# snmp-server trap-source GigabitEthernet0/0/0/2 +# snmp-server throttle-time 60 +# snmp-server community-map cm1 context c1 security-name s1 target-list t1 +# snmp-server inform retries 7 +# snmp-server overload-control 4 6 +# snmp-server ifmib internal cache max-duration 4 +# snmp-server mroutemib send-all-vrf +# snmp-server notification-log-mib size 5 +# snmp-server notification-log-mib GlobalSize 5 +# ------------ +- name: Parse the provided configuration with the existing running configuration + cisco.iosxr.iosxr_snmp_server: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed +# Module Execution Result: +# ------------------------ +# "parsed":{ +# "chassis_id": "test2", +# "communities": [ +# { +# "acl_v4": "test", +# "acl_v6": "test1", +# "name": "test2", +# "ro": true, +# "sdrowner": true +# } +# ], +# "community_maps": [ +# { +# "context": "c1", +# "name": "cm1", +# "security_name": "s1", +# "target_list": "t1" +# } +# ], +# "contact": "t1", +# "context": [ +# "c1", +# "c2" +# ], +# "correlator": { +# "buffer_size": 1024 +# }, +# "drop": { +# "report_IPv4": "test1", +# "unknown_user": true +# }, +# "ifmib": { +# "internal_cache_max_duration": 4 +# }, +# "inform": { +# "retries": 7 +# }, +# "ipv4": { +# "dscp": "af11" +# }, +# "ipv6": { +# "precedence": "routine" +# }, +# "location": "test1", +# "logging_threshold_oid_processing": 1, +# "logging_threshold_pdu_processing": 1, +# "mib_bulkstat_max_procmem_size": 101, +# "mroutemib_send_all_vrf": true, +# "notification_log_mib": { +# "GlobalSize": 5, +# "size": 5 +# }, +# "overload_control": { +# "overload_drop_time": 4, +# "overload_throttle_rate": 6 +# }, +# "packetsize": 490, +# "queue_length": 2, +# "targets": [ +# { +# "host": "1.1.1.2", +# "name": "test" +# }, +# { +# "name": "test2", +# "vrf": "vrf2" +# } +# ], +# "throttle_time": 60, +# "timeouts": { +# "duplicate": 0, +# "inQdrop": 0 +# }, +# "trap": { +# "throttle_time": 12 +# }, +# "trap_source": "GigabitEthernet0/0/0/2", +# "trap_timeout": 3, +# "traps": { +# "addrpool": { +# "high": true, +# "low": true +# }, +# "bfd": true, +# "bgp": { +# "cbgp2": true +# }, +# "bridgemib": true, +# "bulkstat_collection": true, +# "cisco_entity_ext": true, +# "config": true, +# "copy_complete": true, +# "hsrp": true, +# "ipsec": { +# "start": true, +# "stop": true +# }, +# "ipsla": true, +# "l2tun": { +# "sessions": true, +# "tunnel_down": true, +# "tunnel_up": true +# }, +# "l2vpn": { +# "all": true, +# "vc_down": true, +# "vc_up": true +# }, +# "msdp_peer_state_change": true +# }, +# "users": [ +# { +# "Ipv4_acl": "test1", +# "Ipv6_acl": "test2", +# "group": "test2", +# "user": "u1", +# "version": "v1" +# } +# ], +# "vrfs": [ +# { +# "hosts": [ +# { +# "community": "test1", +# "host": "1.1.1.1", +# "traps": true +# } +# ], +# "vrf": "vrf1" +# } +# ] +# } +""" + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.snmp_server.snmp_server import ( + Snmp_serverArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.snmp_server.snmp_server import ( + Snmp_server, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Snmp_serverArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Snmp_server(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_static_routes.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_static_routes.py new file mode 100644 index 00000000..665eb013 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_static_routes.py @@ -0,0 +1,856 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for iosxr_static_routes +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_static_routes +short_description: Resource module to configure static routes. +description: +- This module manages static routes on devices running Cisco IOS-XR. +version_added: 1.0.0 +author: Nilashish Chakraborty (@NilashishC) +options: + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the IOS-XR device + by executing the command B(show running-config router static). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + config: + description: A dictionary of static route options. + type: list + elements: dict + suboptions: + vrf: + description: + - The VRF to which the static route(s) belong. + type: str + address_families: + description: A dictionary specifying the address family to which the static + route(s) belong. + type: list + elements: dict + suboptions: + afi: + description: + - Specifies the top level address family indicator. + type: str + choices: + - ipv4 + - ipv6 + required: true + safi: + description: + - Specifies the subsequent address family indicator. + type: str + choices: + - unicast + - multicast + required: true + routes: + description: A dictionary that specifies the static route configurations. + elements: dict + type: list + suboptions: + dest: + description: + - An IPv4 or IPv6 address in CIDR notation that specifies the destination + network for the static route. + type: str + required: true + next_hops: + description: + - Next hops to the specified destination. + type: list + elements: dict + suboptions: + forward_router_address: + description: + - The IP address of the next hop that can be used to reach the + destination network. + type: str + interface: + description: + - The interface to use to reach the destination. + type: str + dest_vrf: + description: + - The destination VRF. + type: str + admin_distance: + description: + - The administrative distance for this static route. + - Refer to vendor documentation for valid values. + type: int + metric: + description: + - Specifes the metric for this static route. + - Refer to vendor documentation for valid values. + type: int + description: + description: + - Specifies the description for this static route. + type: str + vrflabel: + description: + - Specifies the VRF label for this static route. + - Refer to vendor documentation for valid values. + type: int + tag: + description: + - Specifies a numeric tag for this static route. + - Refer to vendor documentation for valid values. + type: int + track: + description: + - Specifies the object to be tracked. + - This enables object tracking for static routes. + type: str + tunnel_id: + description: + - Specifies a tunnel id for the route. + - Refer to vendor documentation for valid values. + type: int + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - rendered + - parsed + default: merged + +""" +EXAMPLES = """ + +# Using merged + +# Before state +# ------------- +# RP/0/RP0/CPU0:ios#show running-config router static +# Sat Feb 22 07:46:30.089 UTC +# % No such configuration item(s) +# +- name: Merge the provided configuration with the existing running configuration + cisco.iosxr.iosxr_static_routes: + config: + - address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.16/28 + next_hops: + - forward_router_address: 192.0.2.10 + interface: FastEthernet0/0/0/1 + description: LAB + metric: 120 + tag: 10 + + - interface: FastEthernet0/0/0/5 + track: ip_sla_1 + + - dest: 192.0.2.32/28 + next_hops: + - forward_router_address: 192.0.2.11 + admin_distance: 100 + + - afi: ipv6 + safi: unicast + routes: + - dest: 2001:db8:1000::/36 + next_hops: + - interface: FastEthernet0/0/0/7 + description: DC + + - interface: FastEthernet0/0/0/8 + forward_router_address: 2001:db8:2000:2::1 + + - vrf: DEV_SITE + address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.48/28 + next_hops: + - forward_router_address: 192.0.2.12 + description: DEV + dest_vrf: test_1 + + - dest: 192.0.2.80/28 + next_hops: + - interface: FastEthernet0/0/0/2 + forward_router_address: 192.0.2.14 + dest_vrf: test_1 + track: ip_sla_2 + vrflabel: 124 + state: merged + +# After state +# ------------- +# RP/0/RP0/CPU0:ios#show running-config router static +# Sat Feb 22 07:49:11.754 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +# Using merged to update existing static routes + +# Before state +# ------------- +# RP/0/RP0/CPU0:ios#show running-config router static +# Sat Feb 22 07:49:11.754 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Update existing static routes configuration using merged + cisco.iosxr.iosxr_static_routes: + config: + - vrf: DEV_SITE + address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.48/28 + next_hops: + - forward_router_address: 192.0.2.12 + vrflabel: 2301 + dest_vrf: test_1 + + - dest: 192.0.2.80/28 + next_hops: + - interface: FastEthernet0/0/0/2 + forward_router_address: 192.0.2.14 + dest_vrf: test_1 + description: rt_test_1 + state: merged + +# After state +# ------------- +# RP/0/RP0/CPU0:ios#show running-config router static +# Sat Feb 22 07:49:11.754 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV vrflabel 2301 +# 192.0.2.80/28 vrf test_1 192.0.2.14 FastEthernet0/0/0/2 description rt_test_1 track ip_sla_2 vrflabel 124 +# ! +# ! +# ! + +# Using replaced to replace all next hop entries for a single destination network + +# Before state +# -------------- + +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 07:59:08.669 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.48/28 GigabitEthernet0/0/0/1 192.0.3.24 vrflabel 2302 +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Replace device configurations of static routes with provided configurations + cisco.iosxr.iosxr_static_routes: + config: + - vrf: DEV_SITE + address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.48/28 + next_hops: + - forward_router_address: 192.0.2.15 + interface: FastEthernet0/0/0/3 + description: DEV_NEW + dest_vrf: dev_test_2 + state: replaced + +# After state +# ------------ +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 08:04:07.085 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf dev_test_2 FastEthernet0/0/0/3 192.0.2.15 description DEV_NEW +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +# Using overridden to override all static route entries on the device + +# Before state +# ------------- +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 07:59:08.669 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.48/28 GigabitEthernet0/0/0/1 192.0.3.24 vrflabel 2302 +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Overridde all static routes configuration with provided configuration + cisco.iosxr.iosxr_static_routes: + config: + - vrf: DEV_NEW + address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.48/28 + next_hops: + - forward_router_address: 192.0.2.15 + interface: FastEthernet0/0/0/3 + description: DEV1 + - afi: ipv6 + safi: unicast + routes: + - dest: 2001:db8:3000::/36 + next_hops: + - interface: FastEthernet0/0/0/4 + forward_router_address: 2001:db8:2000:2::2 + description: PROD1 + track: ip_sla_1 + state: overridden + +# After state +# ------------- +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 08:07:41.516 UTC +# router static +# vrf DEV_NEW +# address-family ipv4 unicast +# 192.0.2.48/28 FastEthernet0/0/0/3 192.0.2.15 description DEV1 +# ! +# address-family ipv6 unicast +# 2001:db8:3000::/36 FastEthernet0/0/0/4 2001:db8:2000:2::2 description PROD1 track ip_sla_1 +# ! +# ! +# ! + +# Using deleted to delete all destination network entries under a single AFI + +# Before state +# ------------- +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 07:59:08.669 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.48/28 GigabitEthernet0/0/0/1 192.0.3.24 vrflabel 2302 +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Delete all destination network entries under a single AFI + cisco.iosxr.iosxr_static_routes: + config: + - vrf: DEV_SITE + address_families: + - afi: ipv4 + safi: unicast + state: deleted + +# After state +# ------------ + +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 08:16:41.464 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# ! +# ! + +# Using deleted to remove all static route entries from the device + +# Before state +# ------------- +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 07:59:08.669 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.48/28 GigabitEthernet0/0/0/1 192.0.3.24 vrflabel 2302 +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Delete static routes configuration + cisco.iosxr.iosxr_static_routes: + state: deleted + +# After state +# ------------ +# RP/0/RP0/CPU0:ios#sh running-config router static +# Sat Feb 22 08:50:43.038 UTC +# % No such configuration item(s) + +# Using gathered to gather static route facts from the device + +- name: Gather static routes facts from the device using iosxr_static_routes module + cisco.iosxr.iosxr_static_routes: + state: gathered + +# Task output (redacted) +# ----------------------- +# "gathered": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "192.0.2.16/28", +# "next_hops": [ +# { +# "description": "LAB", +# "forward_router_address": "192.0.2.10", +# "interface": "FastEthernet0/0/0/1", +# "metric": 120, +# "tag": 10 +# }, +# { +# "interface": "FastEthernet0/0/0/5", +# "track": "ip_sla_1" +# } +# ] +# }, +# { +# "dest": "192.0.2.32/28", +# "next_hops": [ +# { +# "admin_distance": 100, +# "forward_router_address": "192.0.2.11" +# } +# ] +# } +# ], +# "safi": "unicast" +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2001:db8:1000::/36", +# "next_hops": [ +# { +# "description": "DC", +# "interface": "FastEthernet0/0/0/7" +# }, +# { +# "forward_router_address": "2001:db8:2000:2::1", +# "interface": "FastEthernet0/0/0/8" +# } +# ] +# } +# ], +# "safi": "unicast" +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "192.0.2.48/28", +# "next_hops": [ +# { +# "description": "DEV", +# "dest_vrf": "test_1", +# "forward_router_address": "192.0.2.12" +# }, +# { +# "forward_router_address": "192.0.3.24", +# "interface": "GigabitEthernet0/0/0/1", +# "vrflabel": 2302 +# } +# ] +# }, +# { +# "dest": "192.0.2.80/28", +# "next_hops": [ +# { +# "dest_vrf": "test_1", +# "forward_router_address": "192.0.2.14", +# "interface": "FastEthernet0/0/0/2", +# "track": "ip_sla_2", +# "vrflabel": 124 +# } +# ] +# } +# ], +# "safi": "unicast" +# } +# ], +# "vrf": "DEV_SITE" +# } +# ] + +# Using rendered + +- name: Render platform specific commands (without connecting to the device) + cisco.iosxr.iosxr_static_routes: + config: + - vrf: DEV_SITE + address_families: + - afi: ipv4 + safi: unicast + routes: + - dest: 192.0.2.48/28 + next_hops: + - forward_router_address: 192.0.2.12 + description: DEV + dest_vrf: test_1 + + - dest: 192.0.2.80/28 + next_hops: + - interface: FastEthernet0/0/0/2 + forward_router_address: 192.0.2.14 + dest_vrf: test_1 + track: ip_sla_2 + vrflabel: 124 + +# Task Output (redacted) +# ----------------------- +# "rendered": [ +# "router static"s, +# "vrf DEV_SITE", +# "address-family ipv4 unicast", +# "192.0.2.48/28 vrf test_1 192.0.2.12 description DEV", +# "192.0.2.80/28 vrf test_1 192.0.2.14 FastEthernet0/0/0/2 track ip_sla_2 vrflabel 124" + +# Using parsed + +# parsed.cfg +# ------------ +# Fri Nov 29 21:10:41.896 UTC +# router static +# address-family ipv4 unicast +# 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 +# 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 +# 192.0.2.32/28 192.0.2.11 100 +# ! +# address-family ipv6 unicast +# 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC +# 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 +# ! +# vrf DEV_SITE +# address-family ipv4 unicast +# 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV +# 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 +# ! +# ! +# ! + +- name: Use parsed state to convert externally supplied device specific static routes + commands to structured format + cisco.iosxr.iosxr_static_routes: + running_config: "{{ lookup('file', '../../fixtures/parsed.cfg') }}" + state: parsed + +# Task output (redacted) +# ----------------------- +# "parsed": [ +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "192.0.2.16/28", +# "next_hops": [ +# { +# "description": "LAB", +# "forward_router_address": "192.0.2.10", +# "interface": "FastEthernet0/0/0/1", +# "metric": 120, +# "tag": 10 +# }, +# { +# "interface": "FastEthernet0/0/0/5", +# "track": "ip_sla_1" +# } +# ] +# }, +# { +# "dest": "192.0.2.32/28", +# "next_hops": [ +# { +# "admin_distance": 100, +# "forward_router_address": "192.0.2.11" +# } +# ] +# } +# ], +# "safi": "unicast" +# }, +# { +# "afi": "ipv6", +# "routes": [ +# { +# "dest": "2001:db8:1000::/36", +# "next_hops": [ +# { +# "description": "DC", +# "interface": "FastEthernet0/0/0/7" +# }, +# { +# "forward_router_address": "2001:db8:2000:2::1", +# "interface": "FastEthernet0/0/0/8" +# } +# ] +# } +# ], +# "safi": "unicast" +# } +# ] +# }, +# { +# "address_families": [ +# { +# "afi": "ipv4", +# "routes": [ +# { +# "dest": "192.0.2.48/28", +# "next_hops": [ +# { +# "description": "DEV", +# "dest_vrf": "test_1", +# "forward_router_address": "192.0.2.12" +# } +# ] +# }, +# { +# "dest": "192.0.2.80/28", +# "next_hops": [ +# { +# "dest_vrf": "test_1", +# "forward_router_address": "192.0.2.14", +# "interface": "FastEthernet0/0/0/2", +# "track": "ip_sla_2", +# "vrflabel": 124 +# } +# ] +# } +# ], +# "safi": "unicast" +# } +# ], +# "vrf": "DEV_SITE" +# } +# ] +# } +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + 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: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - router static + - vrf dev_site + - address-family ipv4 unicast + - 192.0.2.48/28 192.0.2.12 FastEthernet0/0/0/1 track ip_sla_10 description dev1 + - address-family ipv6 unicast + - no 2001:db8:1000::/36 + - 2001:db8:3000::/36 2001:db8:2000:2::2 FastEthernet0/0/0/4 track ip_sla_11 description prod1 +""" + + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.argspec.static_routes.static_routes import ( + Static_routesArgs, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.static_routes.static_routes import ( + Static_routes, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [ + ("state", "merged", ("config",)), + ("state", "replaced", ("config",)), + ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), + ] + mutually_exclusive = [("config", "running_config")] + + module = AnsibleModule( + argument_spec=Static_routesArgs.argument_spec, + required_if=required_if, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + result = Static_routes(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_system.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_system.py new file mode 100644 index 00000000..0d0d60ad --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_system.py @@ -0,0 +1,748 @@ +#!/usr/bin/python +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_system +author: +- Peter Sprygada (@privateip) +- Kedar Kekan (@kedarX) +short_description: Module to manage the system attributes. +description: +- This module provides declarative management of node system attributes on Cisco IOS + XR devices. It provides an option to configure host system parameters or remove + those parameters from the device active configuration. +version_added: 1.0.0 +requirements: +- ncclient >= 0.5.3 when using netconf +- lxml >= 4.1.1 when using netconf +extends_documentation_fragment: +- cisco.iosxr.iosxr +notes: +- This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR + Platform Options,../network/user_guide/platform_iosxr.html). +- name-servers I(state=absent) operation with C(netconf) transport is a success, but + with rpc-error. This is due to XR platform issue. Recommended to use I(ignore_errors) + option with the task as a workaround. +options: + hostname: + description: + - Configure the device hostname parameter. This option takes an ASCII string value. + type: str + vrf: + description: + - VRF name for domain services + type: str + default: "default" + domain_name: + description: + - Configure the IP domain name on the remote device to the provided value. Value + should be in the dotted name form and will be appended to the C(hostname) to + create a fully-qualified domain name. + type: str + domain_search: + description: + - Provides the list of domain suffixes to append to the hostname for the purpose + of doing name resolution. This argument accepts a list of names and will be + reconciled with the current active configuration on the running node. + type: list + elements: str + lookup_source: + description: + - The C(lookup_source) argument provides one or more source interfaces to use + for performing DNS lookups. The interface provided in C(lookup_source) must + be a valid interface configured on the device. + type: str + lookup_enabled: + description: + - Provides administrative control for enabling or disabling DNS lookups. When + this argument is set to True, lookups are performed and when it is set to False, + lookups are not performed. + type: bool + default: true + name_servers: + description: + - The C(name_serves) argument accepts a list of DNS name servers by way of either + FQDN or IP address to use to perform name resolution lookups. This argument + accepts wither a list of DNS servers See examples. + type: list + elements: str + state: + description: + - State of the configuration values in the device's current active configuration. When + set to I(present), the values should be configured in the device active configuration + and when set to I(absent) the values should not be in the device active configuration + default: present + choices: + - present + - absent + type: str +""" + +EXAMPLES = """ +- name: configure hostname and domain-name (default vrf=default) + cisco.iosxr.iosxr_system: + hostname: iosxr01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - cisco.com +- name: remove configuration + cisco.iosxr.iosxr_system: + hostname: iosxr01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - cisco.com + state: absent +- name: configure hostname and domain-name with vrf + cisco.iosxr.iosxr_system: + hostname: iosxr01 + vrf: nondefault + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - cisco.com +- name: configure DNS lookup sources + cisco.iosxr.iosxr_system: + lookup_source: MgmtEth0/0/CPU0/0 + lookup_enabled: true +- name: configure name servers + cisco.iosxr.iosxr_system: + name_servers: + - 8.8.8.8 + - 8.8.4.4 +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - hostname iosxr01 + - ip domain-name test.example.com +xml: + description: NetConf rpc xml sent to device with transport C(netconf) + returned: always (empty list when no xml rpc to send) + type: list + sample: + - '<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <ip-domain xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-domain-cfg"> + <vrfs> + <vrf> + <vrf-name>default</vrf-name> + <lists> + <list xc:operation="merge"> + <order>0</order> + <list-name>redhat.com</list-name> + </list> + </lists> + </vrf> + </vrfs> + </ip-domain> + </config>' +""" + +import collections +import re + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + build_xml, + etree_find, + etree_findall, + get_config, + is_cliconf, + is_netconf, + load_config, +) + + +def diff_list(want, have): + adds = set(want).difference(have) + removes = set(have).difference(want) + return (adds, removes) + + +class ConfigBase(object): + def __init__(self, module): + self._module = module + self._result = {"changed": False, "warnings": []} + self._want = dict() + self._have = dict() + + def map_params_to_obj(self): + self._want.update( + { + "hostname": self._module.params["hostname"], + "vrf": self._module.params["vrf"], + "domain_name": self._module.params["domain_name"], + "domain_search": self._module.params["domain_search"], + "lookup_source": self._module.params["lookup_source"], + "lookup_enabled": self._module.params["lookup_enabled"], + "name_servers": self._module.params["name_servers"], + }, + ) + + +class CliConfiguration(ConfigBase): + def __init__(self, module): + super(CliConfiguration, self).__init__(module) + + def map_obj_to_commands(self): + commands = list() + state = self._module.params["state"] + + def needs_update(x): + return self._want.get(x) and (self._want.get(x) != self._have.get(x)) + + if state == "absent": + if self._have["hostname"] != "ios": + commands.append("no hostname") + if self._have["domain_name"]: + commands.append("no domain name") + if self._have["lookup_source"]: + commands.append( + "no domain lookup source-interface {0!s}".format(self._have["lookup_source"]), + ) + if not self._have["lookup_enabled"]: + commands.append("no domain lookup disable") + for item in self._have["name_servers"]: + commands.append("no domain name-server {0!s}".format(item)) + for item in self._have["domain_search"]: + commands.append("no domain list {0!s}".format(item)) + + elif state == "present": + if needs_update("hostname"): + commands.append("hostname {0!s}".format(self._want["hostname"])) + + if needs_update("domain_name"): + commands.append("domain name {0!s}".format(self._want["domain_name"])) + + if needs_update("lookup_source"): + commands.append( + "domain lookup source-interface {0!s}".format(self._want["lookup_source"]), + ) + + cmd = None + if not self._want["lookup_enabled"] and self._have["lookup_enabled"]: + cmd = "domain lookup disable" + elif self._want["lookup_enabled"] and not self._have["lookup_enabled"]: + cmd = "no domain lookup disable" + if cmd is not None: + commands.append(cmd) + + if self._want["name_servers"] is not None: + adds, removes = diff_list(self._want["name_servers"], self._have["name_servers"]) + for item in adds: + commands.append("domain name-server {0!s}".format(item)) + for item in removes: + commands.append("no domain name-server {0!s}".format(item)) + + if self._want["domain_search"] is not None: + adds, removes = diff_list(self._want["domain_search"], self._have["domain_search"]) + for item in adds: + commands.append("domain list {0!s}".format(item)) + for item in removes: + commands.append("no domain list {0!s}".format(item)) + + self._result["commands"] = [] + if commands: + commit = not self._module.check_mode + diff = load_config(self._module, commands, commit=commit) + if diff: + self._result["diff"] = dict(prepared=diff) + + self._result["commands"] = commands + self._result["changed"] = True + + def parse_hostname(self, config): + match = re.search(r"^hostname (\S+)", config, re.M) + if match: + return match.group(1) + + def parse_domain_name(self, config): + match = re.search(r"^domain name (\S+)", config, re.M) + if match: + return match.group(1) + + def parse_lookup_source(self, config): + match = re.search(r"^domain lookup source-interface (\S+)", config, re.M) + if match: + return match.group(1) + + def map_config_to_obj(self): + config = get_config(self._module) + self._have.update( + { + "hostname": self.parse_hostname(config), + "domain_name": self.parse_domain_name(config), + "domain_search": re.findall(r"^domain list (\S+)", config, re.M), + "lookup_source": self.parse_lookup_source(config), + "lookup_enabled": "domain lookup disable" not in config, + "name_servers": re.findall(r"^domain name-server (\S+)", config, re.M), + }, + ) + + def run(self): + self.map_params_to_obj() + self.map_config_to_obj() + self.map_obj_to_commands() + + return self._result + + +class NCConfiguration(ConfigBase): + def __init__(self, module): + super(NCConfiguration, self).__init__(module) + self._system_meta = collections.OrderedDict() + self._system_domain_meta = collections.OrderedDict() + self._system_server_meta = collections.OrderedDict() + self._hostname_meta = collections.OrderedDict() + self._lookup_source_meta = collections.OrderedDict() + self._lookup_meta = collections.OrderedDict() + + def map_obj_to_xml_rpc(self): + self._system_meta.update( + [ + ("vrfs", {"xpath": "ip-domain/vrfs", "tag": True, "operation": "edit"}), + ("vrf", {"xpath": "ip-domain/vrfs/vrf", "tag": True, "operation": "edit"}), + ("a:vrf", {"xpath": "ip-domain/vrfs/vrf/vrf-name", "operation": "edit"}), + ( + "a:domain_name", + { + "xpath": "ip-domain/vrfs/vrf/name", + "operation": "edit", + "attrib": "operation", + }, + ), + ], + ) + + self._system_domain_meta.update( + [ + ("vrfs", {"xpath": "ip-domain/vrfs", "tag": True, "operation": "edit"}), + ("vrf", {"xpath": "ip-domain/vrfs/vrf", "tag": True, "operation": "edit"}), + ("a:vrf", {"xpath": "ip-domain/vrfs/vrf/vrf-name", "operation": "edit"}), + ("lists", {"xpath": "ip-domain/vrfs/vrf/lists", "tag": True, "operation": "edit"}), + ( + "list", + { + "xpath": "ip-domain/vrfs/vrf/lists/list", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ("a:order", {"xpath": "ip-domain/vrfs/vrf/lists/list/order", "operation": "edit"}), + ( + "a:domain_search", + {"xpath": "ip-domain/vrfs/vrf/lists/list/list-name", "operation": "edit"}, + ), + ], + ) + + self._system_server_meta.update( + [ + ("vrfs", {"xpath": "ip-domain/vrfs", "tag": True, "operation": "edit"}), + ("vrf", {"xpath": "ip-domain/vrfs/vrf", "tag": True, "operation": "edit"}), + ("a:vrf", {"xpath": "ip-domain/vrfs/vrf/vrf-name", "operation": "edit"}), + ( + "servers", + {"xpath": "ip-domain/vrfs/vrf/servers", "tag": True, "operation": "edit"}, + ), + ( + "server", + { + "xpath": "ip-domain/vrfs/vrf/servers/server", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ( + "a:order", + {"xpath": "ip-domain/vrfs/vrf/servers/server/order", "operation": "edit"}, + ), + ( + "a:name_servers", + { + "xpath": "ip-domain/vrfs/vrf/servers/server/server-address", + "operation": "edit", + }, + ), + ], + ) + + self._hostname_meta.update( + [ + ( + "a:hostname", + {"xpath": "host-names/host-name", "operation": "edit", "attrib": "operation"}, + ), + ], + ) + + self._lookup_source_meta.update( + [ + ("vrfs", {"xpath": "ip-domain/vrfs", "tag": True, "operation": "edit"}), + ("vrf", {"xpath": "ip-domain/vrfs/vrf", "tag": True, "operation": "edit"}), + ("a:vrf", {"xpath": "ip-domain/vrfs/vrf/vrf-name", "operation": "edit"}), + ( + "a:lookup_source", + { + "xpath": "ip-domain/vrfs/vrf/source-interface", + "operation": "edit", + "attrib": "operation", + }, + ), + ], + ) + + self._lookup_meta.update( + [ + ("vrfs", {"xpath": "ip-domain/vrfs", "tag": True, "operation": "edit"}), + ("vrf", {"xpath": "ip-domain/vrfs/vrf", "tag": True, "operation": "edit"}), + ("a:vrf", {"xpath": "ip-domain/vrfs/vrf/vrf-name", "operation": "edit"}), + ( + "lookup", + { + "xpath": "ip-domain/vrfs/vrf/lookup", + "tag": True, + "operation": "edit", + "attrib": "operation", + }, + ), + ], + ) + + state = self._module.params["state"] + _get_filter = build_xml("ip-domain", opcode="filter") + running = get_config(self._module, source="running", config_filter=_get_filter) + _get_filter = build_xml("host-names", opcode="filter") + hostname_runn = get_config(self._module, source="running", config_filter=_get_filter) + + hostname_ele = etree_find(hostname_runn, "host-name") + hostname = hostname_ele.text if hostname_ele is not None else None + + vrf_ele = etree_findall(running, "vrf") + vrf_map = {} + for vrf in vrf_ele: + name_server_list = list() + domain_list = list() + vrf_name_ele = etree_find(vrf, "vrf-name") + vrf_name = vrf_name_ele.text if vrf_name_ele is not None else None + + domain_name_ele = etree_find(vrf, "name") + domain_name = domain_name_ele.text if domain_name_ele is not None else None + + domain_ele = etree_findall(vrf, "list-name") + for domain in domain_ele: + domain_list.append(domain.text) + + server_ele = etree_findall(vrf, "server-address") + for server in server_ele: + name_server_list.append(server.text) + + lookup_source_ele = etree_find(vrf, "source-interface") + lookup_source = lookup_source_ele.text if lookup_source_ele is not None else None + + lookup_enabled = False if etree_find(vrf, "lookup") is not None else True + + vrf_map[vrf_name] = { + "domain_name": domain_name, + "domain_search": domain_list, + "name_servers": name_server_list, + "lookup_source": lookup_source, + "lookup_enabled": lookup_enabled, + } + + opcode = None + hostname_param = {} + lookup_param = {} + system_param = {} + sys_server_params = list() + sys_domain_params = list() + add_domain_params = list() + del_domain_params = list() + add_server_params = list() + del_server_params = list() + lookup_source_params = {} + + try: + sys_node = vrf_map[self._want["vrf"]] + except KeyError: + sys_node = { + "domain_name": None, + "domain_search": [], + "name_servers": [], + "lookup_source": None, + "lookup_enabled": True, + } + + if state == "absent": + opcode = "delete" + + def needs_update(x): + return self._want[x] is not None and self._want[x] == sys_node[x] + + if needs_update("domain_name"): + system_param = {"vrf": self._want["vrf"], "domain_name": self._want["domain_name"]} + + if needs_update("hostname"): + hostname_param = {"hostname": hostname} + + if not self._want["lookup_enabled"] and not sys_node["lookup_enabled"]: + lookup_param["vrf"] = self._want["vrf"] + + if needs_update("lookup_source"): + lookup_source_params["vrf"] = self._want["vrf"] + lookup_source_params["lookup_source"] = self._want["lookup_source"] + + if self._want["domain_search"]: + domain_param = {} + domain_param["domain_name"] = self._want["domain_name"] + domain_param["vrf"] = self._want["vrf"] + domain_param["order"] = "0" + for domain in self._want["domain_search"]: + if domain in sys_node["domain_search"]: + domain_param["domain_search"] = domain + sys_domain_params.append(domain_param.copy()) + + if self._want["name_servers"]: + server_param = {} + server_param["vrf"] = self._want["vrf"] + server_param["order"] = "0" + for server in self._want["name_servers"]: + if server in sys_node["name_servers"]: + server_param["name_servers"] = server + sys_server_params.append(server_param.copy()) + + elif state == "present": + opcode = "merge" + + def needs_update(x): + return self._want[x] is not None and ( + sys_node[x] is None + or (sys_node[x] is not None and self._want[x] != sys_node[x]) + ) + + if needs_update("domain_name"): + system_param = {"vrf": self._want["vrf"], "domain_name": self._want["domain_name"]} + + if self._want["hostname"] is not None and self._want["hostname"] != hostname: + hostname_param = {"hostname": self._want["hostname"]} + + if not self._want["lookup_enabled"] and sys_node["lookup_enabled"]: + lookup_param["vrf"] = self._want["vrf"] + + if needs_update("lookup_source"): + lookup_source_params["vrf"] = self._want["vrf"] + lookup_source_params["lookup_source"] = self._want["lookup_source"] + + if self._want["domain_search"]: + domain_adds, domain_removes = diff_list( + self._want["domain_search"], + sys_node["domain_search"], + ) + domain_param = {} + domain_param["domain_name"] = self._want["domain_name"] + domain_param["vrf"] = self._want["vrf"] + domain_param["order"] = "0" + for domain in domain_adds: + if domain not in sys_node["domain_search"]: + domain_param["domain_search"] = domain + add_domain_params.append(domain_param.copy()) + for domain in domain_removes: + if domain in sys_node["domain_search"]: + domain_param["domain_search"] = domain + del_domain_params.append(domain_param.copy()) + + if self._want["name_servers"]: + server_adds, server_removes = diff_list( + self._want["name_servers"], + sys_node["name_servers"], + ) + server_param = {} + server_param["vrf"] = self._want["vrf"] + server_param["order"] = "0" + for domain in server_adds: + if domain not in sys_node["name_servers"]: + server_param["name_servers"] = domain + add_server_params.append(server_param.copy()) + for domain in server_removes: + if domain in sys_node["name_servers"]: + server_param["name_servers"] = domain + del_server_params.append(server_param.copy()) + + self._result["xml"] = [] + _edit_filter_list = list() + if opcode: + if hostname_param: + _edit_filter_list.append( + build_xml( + "host-names", + xmap=self._hostname_meta, + params=hostname_param, + opcode=opcode, + ), + ) + + if system_param: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_meta, + params=system_param, + opcode=opcode, + ), + ) + + if lookup_source_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._lookup_source_meta, + params=lookup_source_params, + opcode=opcode, + ), + ) + if lookup_param: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._lookup_meta, + params=lookup_param, + opcode=opcode, + ), + ) + + if opcode == "delete": + if sys_domain_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_domain_meta, + params=sys_domain_params, + opcode=opcode, + ), + ) + if sys_server_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_server_meta, + params=sys_server_params, + opcode=opcode, + ), + ) + if self._want["vrf"] != "default": + self._result["warnings"] = [ + "name-servers delete operation with non-default vrf is a success, " + "but with rpc-error. Recommended to use 'ignore_errors' option with the task as a workaround", + ] + elif opcode == "merge": + if add_domain_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_domain_meta, + params=add_domain_params, + opcode=opcode, + ), + ) + if del_domain_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_domain_meta, + params=del_domain_params, + opcode="delete", + ), + ) + + if add_server_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_server_meta, + params=add_server_params, + opcode=opcode, + ), + ) + if del_server_params: + _edit_filter_list.append( + build_xml( + "ip-domain", + xmap=self._system_server_meta, + params=del_server_params, + opcode="delete", + ), + ) + + diff = None + if _edit_filter_list: + commit = not self._module.check_mode + diff = load_config( + self._module, + _edit_filter_list, + commit=commit, + running=running, + nc_get_filter=_get_filter, + ) + + if diff: + if self._module._diff: + self._result["diff"] = dict(prepared=diff) + + self._result["xml"] = _edit_filter_list + self._result["changed"] = True + + def run(self): + self.map_params_to_obj() + self.map_obj_to_xml_rpc() + + return self._result + + +def main(): + """Main entry point for Ansible module execution""" + argument_spec = dict( + hostname=dict(type="str"), + vrf=dict(type="str", default="default"), + domain_name=dict(type="str"), + domain_search=dict(type="list", elements="str"), + name_servers=dict(type="list", elements="str"), + lookup_source=dict(type="str"), + lookup_enabled=dict(type="bool", default=True), + state=dict(choices=["present", "absent"], default="present"), + ) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + config_object = None + if is_cliconf(module): + # Commenting the below cliconf deprecation support call for Ansible 2.9 as it'll be continued to be supported + config_object = CliConfiguration(module) + elif is_netconf(module): + config_object = NCConfiguration(module) + + result = None + if config_object: + result = config_object.run() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_user.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_user.py new file mode 100644 index 00000000..6aefaa72 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_user.py @@ -0,0 +1,905 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2017, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +DOCUMENTATION = """ +module: iosxr_user +author: +- Trishna Guha (@trishnaguha) +- Sebastiaan van Doesselaar (@sebasdoes) +- Kedar Kekan (@kedarX) +short_description: Module to manage the aggregates of local users. +description: +- This module provides declarative management of the local usernames configured on + network devices. It allows playbooks to manage either individual usernames or the + aggregate of usernames in the current running config. It also supports purging usernames + from the configuration that are not explicitly defined. +version_added: 1.0.0 +extends_documentation_fragment: +- cisco.iosxr.iosxr +notes: +- This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR + Platform Options,../network/user_guide/platform_iosxr.html). +options: + aggregate: + description: + - The set of username objects to be configured on the remote Cisco IOS XR device. + The list entries can either be the username or a hash of username and properties. + This argument is mutually exclusive with the C(name) argument. + aliases: + - users + - collection + type: list + elements: dict + suboptions: + name: + description: + - The username to be configured on the Cisco IOS XR device. This argument accepts + a string value and is mutually exclusive with the C(aggregate) argument. Please + note that this option is not same as C(provider username). + type: str + required: true + configured_password: + description: + - The password to be configured on the Cisco IOS XR device. The password needs + to be provided in clear text. Password is encrypted on the device when used + with I(cli) and by Ansible when used with I(netconf) using the same MD5 hash + technique with salt size of 3. Please note that this option is not same as C(provider + password). + type: str + update_password: + description: + - Since passwords are encrypted in the device running config, this argument will + instruct the module when to change the password. When set to C(always), the + password will always be updated in the device and when set to C(on_create) the + password will be updated only if the username is created. + type: str + choices: + - on_create + - always + group: + description: + - Configures the group for the username in the device running configuration. The + argument accepts a string value defining the group name. This argument does + not check if the group has been configured on the device. + type: str + aliases: + - role + groups: + description: + - Configures the groups for the username in the device running configuration. + The argument accepts a list of group names. This argument does not check if + the group has been configured on the device. It is similar to the aggregate + command for usernames, but lets you configure multiple groups for the user(s). + type: list + elements: str + admin: + description: + - Enters into administration configuration mode for making config changes to the + device. + - Applicable only when using network_cli transport + type: bool + state: + description: + - Configures the state of the username definition as it relates to the device + operational configuration. When set to I(present), the username(s) should be + configured in the device active configuration and when set to I(absent) the + username(s) should not be in the device active configuration + type: str + choices: + - present + - absent + public_key: + description: + - Configures the contents of the public keyfile to upload to the IOS-XR node. + This enables users to login using the accompanying private key. IOS-XR only + accepts base64 decoded files, so this will be decoded and uploaded to the node. + Do note that this requires an OpenSSL public key file, PuTTy generated files + will not work! Mutually exclusive with public_key_contents. If used with multiple + users in aggregates, then the same key file is used for all users. + type: str + public_key_contents: + description: + - Configures the contents of the public keyfile to upload to the IOS-XR node. + This enables users to login using the accompanying private key. IOS-XR only + accepts base64 decoded files, so this will be decoded and uploaded to the node. + Do note that this requires an OpenSSL public key file, PuTTy generated files + will not work! Mutually exclusive with public_key.If used with multiple users + in aggregates, then the same key file is used for all users. + type: str + name: + description: + - The username to be configured on the Cisco IOS XR device. This argument accepts + a string value and is mutually exclusive with the C(aggregate) argument. Please + note that this option is not same as C(provider username). + type: str + configured_password: + description: + - The password to be configured on the Cisco IOS XR device. The password needs + to be provided in clear text. Password is encrypted on the device when used + with I(cli) and by Ansible when used with I(netconf) using the same MD5 hash + technique with salt size of 3. Please note that this option is not same as C(provider + password). + type: str + update_password: + description: + - Since passwords are encrypted in the device running config, this argument will + instruct the module when to change the password. When set to C(always), the + password will always be updated in the device and when set to C(on_create) the + password will be updated only if the username is created. + type: str + default: always + choices: + - on_create + - always + group: + description: + - Configures the group for the username in the device running configuration. The + argument accepts a string value defining the group name. This argument does + not check if the group has been configured on the device. + type: str + aliases: + - role + groups: + description: + - Configures the groups for the username in the device running configuration. + The argument accepts a list of group names. This argument does not check if + the group has been configured on the device. It is similar to the aggregate + command for usernames, but lets you configure multiple groups for the user(s). + type: list + elements: str + purge: + description: + - Instructs the module to consider the resource definition absolute. It will remove + any previously configured usernames on the device with the exception of the + `admin` user and the current defined set of users. + type: bool + default: false + admin: + description: + - Enters into administration configuration mode for making config changes to the + device. + - Applicable only when using network_cli transport + type: bool + default: false + state: + description: + - Configures the state of the username definition as it relates to the device + operational configuration. When set to I(present), the username(s) should be + configured in the device active configuration and when set to I(absent) the + username(s) should not be in the device active configuration + type: str + default: present + choices: + - present + - absent + public_key: + description: + - Configures the contents of the public keyfile to upload to the IOS-XR node. + This enables users to login using the accompanying private key. IOS-XR only + accepts base64 decoded files, so this will be decoded and uploaded to the node. + Do note that this requires an OpenSSL public key file, PuTTy generated files + will not work! Mutually exclusive with public_key_contents. If used with multiple + users in aggregates, then the same key file is used for all users. + type: str + public_key_contents: + description: + - Configures the contents of the public keyfile to upload to the IOS-XR node. + This enables users to login using the accompanying private key. IOS-XR only + accepts base64 decoded files, so this will be decoded and uploaded to the node. + Do note that this requires an OpenSSL public key file, PuTTy generated files + will not work! Mutually exclusive with public_key.If used with multiple users + in aggregates, then the same key file is used for all users. + type: str + +requirements: +- ncclient >= 0.5.3 when using netconf +- lxml >= 4.1.1 when using netconf +- base64 when using I(public_key_contents) or I(public_key) +""" + +EXAMPLES = """ +- name: create a new user + cisco.iosxr.iosxr_user: + name: ansible + configured_password: mypassword + state: present +- name: create a new user in admin configuration mode + cisco.iosxr.iosxr_user: + name: ansible + configured_password: mypassword + admin: true + state: present +- name: remove all users except admin + cisco.iosxr.iosxr_user: + purge: true +- name: set multiple users to group sys-admin + cisco.iosxr.iosxr_user: + aggregate: + - name: netop + - name: netend + group: sysadmin + state: present +- name: set multiple users to multiple groups + cisco.iosxr.iosxr_user: + aggregate: + - name: netop + - name: netend + groups: + - sysadmin + - root-system + state: present +- name: Change Password for User netop + cisco.iosxr.iosxr_user: + name: netop + configured_password: '{{ new_password }}' + update_password: always + state: present +- name: Add private key authentication for user netop + cisco.iosxr.iosxr_user: + name: netop + state: present + public_key_contents: "{{ lookup('file', '/home/netop/.ssh/id_rsa.pub' }}" +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - username ansible secret password group sysadmin + - username admin secret admin +xml: + description: NetConf rpc xml sent to device with transport C(netconf) + returned: always (empty list when no xml rpc to send) + type: list + sample: + - '<config xmlns:xc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"> + <aaa xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-lib-cfg\"> + <usernames xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XR-aaa-locald-cfg\"> + <username xc:operation=\"merge\"> + <name>test7</name> + <usergroup-under-usernames> + <usergroup-under-username> + <name>sysadmin</name> + </usergroup-under-username> + </usergroup-under-usernames> + <secret>$1$ZsXC$zZ50wqhDC543ZWQkkAHLW0</secret> + </username> + </usernames> + </aaa> + </config>' +""" + +import collections +import os + +from copy import deepcopy +from functools import partial + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_default_spec, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + build_xml, + copy_file, + etree_findall, + get_capabilities, + get_config, + get_connection, + is_cliconf, + is_netconf, + load_config, +) +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import Version + + +try: + from base64 import b64decode + + HAS_B64 = True +except ImportError: + HAS_B64 = False + + +class PublicKeyManager(object): + def __init__(self, module, result): + self._module = module + self._result = result + + def convert_key_to_base64(self): + """IOS-XR only accepts base64 decoded files, this converts the public key to a temp file.""" + if self._module.params["aggregate"]: + name = "aggregate" + else: + name = self._module.params["name"] + + if self._module.params["public_key_contents"]: + key = self._module.params["public_key_contents"] + elif self._module.params["public_key"]: + readfile = open(self._module.params["public_key"], "r") + key = readfile.read() + splitfile = key.split()[1] + + base64key = b64decode(splitfile) + base64file = open("/tmp/publickey_%s.b64" % (name), "wb") + base64file.write(base64key) + base64file.close() + + return "/tmp/publickey_%s.b64" % (name) + + def copy_key_to_node(self, base64keyfile): + """Copy key to IOS-XR node. We use SFTP because older IOS-XR versions don't handle SCP very well.""" + + if self._module.params["aggregate"]: + name = "aggregate" + else: + name = self._module.params["name"] + + src = base64keyfile + dst = "/harddisk:/publickey_%s.b64" % (name) + + copy_file(self._module, src, dst) + + def addremovekey(self, command): + """Add or remove key based on command""" + admin = self._module.params.get("admin") + + conn = get_connection(self._module) + if admin: + conn.send_command("admin") + out = conn.send_command(command, prompt="yes/no", answer="yes") + if admin: + conn.send_command("exit") + + return out + + def run(self): + + if self._module.params["state"] == "present": + if not self._module.check_mode: + key = self.convert_key_to_base64() + self.copy_key_to_node(key) + + if self._module.params["aggregate"]: + for user in self._module.params["aggregate"]: + cmdtodo = ( + "crypto key import authentication rsa username %s harddisk:/publickey_aggregate.b64" + % (user) + ) + self.addremovekey(cmdtodo) + else: + cmdtodo = ( + "crypto key import authentication rsa username %s harddisk:/publickey_%s.b64" + % (self._module.params["name"], self._module.params["name"]) + ) + self.addremovekey(cmdtodo) + elif self._module.params["state"] == "absent": + if not self._module.check_mode: + if self._module.params["aggregate"]: + for user in self._module.params["aggregate"]: + cmdtodo = "crypto key zeroize authentication rsa username %s" % (user) + self.addremovekey(cmdtodo) + else: + cmdtodo = "crypto key zeroize authentication rsa username %s" % ( + self._module.params["name"] + ) + self.addremovekey(cmdtodo) + elif self._module.params["purge"] is True: + if not self._module.check_mode: + cmdtodo = "crypto key zeroize authentication rsa all" + self.addremovekey(cmdtodo) + + return self._result + + +def search_obj_in_list(name, lst): + for o in lst: + if o["name"] == name: + return o + + return None + + +class ConfigBase(object): + def __init__(self, module, result, flag=None): + self._module = module + self._result = result + self._want = list() + self._have = list() + + def get_param_value(self, key, item): + # if key doesn't exist in the item, get it from module.params + if not item.get(key): + value = self._module.params[key] + + # if key does exist, do a type check on it to validate it + else: + value_type = self._module.argument_spec[key].get("type", "str") + type_checker = self._module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] + type_checker(item[key]) + value = item[key] + + # validate the param value (if validator func exists) + validator = globals().get("validate_%s" % key) + if all((value, validator)): + validator(value, self._module) + + return value + + def map_params_to_obj(self): + users = self._module.params["aggregate"] + + aggregate = list() + if not users: + if not self._module.params["name"] and self._module.params["purge"]: + pass + elif not self._module.params["name"]: + self._module.fail_json(msg="username is required") + else: + aggregate = [{"name": self._module.params["name"]}] + else: + for item in users: + if not isinstance(item, dict): + aggregate.append({"name": item}) + elif "name" not in item: + self._module.fail_json(msg="name is required") + else: + aggregate.append(item) + + for item in aggregate: + get_value = partial(self.get_param_value, item=item) + item["configured_password"] = get_value("configured_password") + item["group"] = get_value("group") + item["groups"] = get_value("groups") + item["state"] = get_value("state") + self._want.append(item) + + +class CliConfiguration(ConfigBase): + def __init__(self, module, result): + super(CliConfiguration, self).__init__(module, result) + + def map_config_to_obj(self): + data = get_config(self._module, config_filter="username") + + if "No such configuration item" in data: + return + + users = data.strip().rstrip("!").split("!") + + for user in users: + user_config = user.strip().splitlines() + + name = user_config[0].strip().split()[1] + group = None + + if len(user_config) > 1: + group_or_secret = user_config[1].strip().split() + if group_or_secret[0] == "group": + group = group_or_secret[1] + + obj = {"name": name, "state": "present", "configured_password": None, "group": group} + self._have.append(obj) + + def map_obj_to_commands(self): + commands = list() + + for w in self._want: + name = w["name"] + state = w["state"] + + obj_in_have = search_obj_in_list(name, self._have) + + if state == "absent" and obj_in_have: + commands.append("no username " + name) + elif state == "present" and not obj_in_have: + user_cmd = "username " + name + commands.append(user_cmd) + + if w["configured_password"]: + commands.append(user_cmd + " secret " + w["configured_password"]) + if w["group"]: + commands.append(user_cmd + " group " + w["group"]) + elif w["groups"]: + for group in w["groups"]: + commands.append(user_cmd + " group " + group) + + elif state == "present" and obj_in_have: + user_cmd = "username " + name + + if self._module.params["update_password"] == "always" and w["configured_password"]: + commands.append(user_cmd + " secret " + w["configured_password"]) + if w["group"] and w["group"] != obj_in_have["group"]: + commands.append(user_cmd + " group " + w["group"]) + elif w["groups"]: + for group in w["groups"]: + commands.append(user_cmd + " group " + group) + + if self._module.params["purge"]: + want_users = [x["name"] for x in self._want] + have_users = [x["name"] for x in self._have] + for item in set(have_users).difference(set(want_users)): + if item != "admin": + commands.append("no username %s" % item) + + if "no username admin" in commands: + self._module.fail_json(msg="cannot delete the `admin` account") + + self._result["commands"] = [] + if commands: + commit = not self._module.check_mode + admin = self._module.params["admin"] + diff = load_config(self._module, commands, commit=commit, admin=admin) + if diff: + self._result["diff"] = dict(prepared=diff) + + self._result["commands"] = commands + self._result["changed"] = True + + def run(self): + self.map_params_to_obj() + self.map_config_to_obj() + self.map_obj_to_commands() + + return self._result + + +class NCConfiguration(ConfigBase): + def __init__(self, module, result): + super(NCConfiguration, self).__init__(module, result) + self._locald_meta = collections.OrderedDict() + self._locald_group_meta = collections.OrderedDict() + + def generate_md5_hash(self, arg): + """ + Generate MD5 hash with randomly generated salt size of 3. + :param arg: + :return passwd: + """ + cmd = "openssl passwd -salt `openssl rand -base64 3` -1 " + return os.popen(cmd + arg).readlines()[0].strip() + + def map_obj_to_xml_rpc(self, os_version): + if os_version and Version(os_version) > Version("7.0"): + self._locald_meta.update( + [ + ("aaa_locald", {"xpath": "aaa/usernames", "tag": True, "ns": True}), + ( + "username", + {"xpath": "aaa/usernames/username", "tag": True, "attrib": "operation"}, + ), + ("a:name", {"xpath": "aaa/usernames/username/name"}), + ("a:ordering_index", {"xpath": "aaa/usernames/username/ordering-index"}), + ( + "secret", + { + "xpath": "aaa/usernames/username/secret", + "tag": True, + "operation": "edit", + }, + ), + ("a:type", {"xpath": "aaa/usernames/username/secret/type", "value": "type5"}), + ( + "a:configured_password", + {"xpath": "aaa/usernames/username/secret/secret5", "operation": "edit"}, + ), + ], + ) + self._locald_group_meta.update( + [ + ("aaa_locald", {"xpath": "aaa/usernames", "tag": True, "ns": True}), + ( + "username", + {"xpath": "aaa/usernames/username", "tag": True, "attrib": "operation"}, + ), + ("a:name", {"xpath": "aaa/usernames/username/name"}), + ("a:ordering_index", {"xpath": "aaa/usernames/username/ordering-index"}), + ( + "usergroups", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames", + "tag": True, + "operation": "edit", + }, + ), + ( + "usergroup", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames/usergroup-under-username", + "tag": True, + "operation": "edit", + }, + ), + ( + "a:group", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames/usergroup-under-username/name", + "operation": "edit", + }, + ), + ], + ) + else: + self._locald_meta.update( + [ + ("aaa_locald", {"xpath": "aaa/usernames", "tag": True, "ns": True}), + ( + "username", + {"xpath": "aaa/usernames/username", "tag": True, "attrib": "operation"}, + ), + ("a:name", {"xpath": "aaa/usernames/username/name"}), + ( + "a:configured_password", + {"xpath": "aaa/usernames/username/secret", "operation": "edit"}, + ), + ], + ) + self._locald_group_meta.update( + [ + ("aaa_locald", {"xpath": "aaa/usernames", "tag": True, "ns": True}), + ( + "username", + {"xpath": "aaa/usernames/username", "tag": True, "attrib": "operation"}, + ), + ("a:name", {"xpath": "aaa/usernames/username/name"}), + ( + "usergroups", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames", + "tag": True, + "operation": "edit", + }, + ), + ( + "usergroup", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames/usergroup-under-username", + "tag": True, + "operation": "edit", + }, + ), + ( + "a:group", + { + "xpath": "aaa/usernames/username/usergroup-under-usernames/usergroup-under-username/name", + "operation": "edit", + }, + ), + ], + ) + + state = self._module.params["state"] + _get_filter = build_xml("aaa", opcode="filter") + running = get_config(self._module, source="running", config_filter=_get_filter) + + elements = etree_findall(running, "username") + users = list() + for element in elements: + name_list = etree_findall(element, "name") + users.append(name_list[0].text) + list_size = len(name_list) + if list_size == 1: + self._have.append({"name": name_list[0].text, "group": None, "groups": None}) + elif list_size == 2: + self._have.append( + {"name": name_list[0].text, "group": name_list[1].text, "groups": None}, + ) + elif list_size > 2: + name_iter = iter(name_list) + next(name_iter) + tmp_list = list() + for name in name_iter: + tmp_list.append(name.text) + + self._have.append({"name": name_list[0].text, "group": None, "groups": tmp_list}) + if os_version and Version(os_version) > Version("7.0"): + ordering_index = etree_findall(element, "ordering-index") + if len(self._have) > 0: + self._have[-1].update(ordering_index=ordering_index[0].text) + + locald_params = list() + locald_group_params = list() + opcode = None + ordering_index_list = [ + int(user.get("ordering_index")) for user in self._have if user.get("ordering_index") + ] + + if state == "absent": + opcode = "delete" + for want_item in self._want: + if want_item["name"] in users: + obj_in_have = search_obj_in_list(want_item["name"], self._have) + if os_version and Version(os_version) > Version("7.0"): + want_item["ordering_index"] = obj_in_have["ordering_index"] + want_item["configured_password"] = None + locald_params.append(want_item) + elif state == "present": + opcode = "merge" + for want_item in self._want: + obj_in_have = search_obj_in_list(want_item["name"], self._have) + if want_item["name"] not in users: + if os_version and Version(os_version) > Version("7.0"): + want_item["configured_password"] = self.generate_md5_hash( + want_item["configured_password"], + ) + new_ordering_index = ordering_index_list[-1] + 1 + want_item["ordering_index"] = str(new_ordering_index) + ordering_index_list.append(new_ordering_index) + want_item["type"] = "type5" + want_item["configured_password"] = self.generate_md5_hash( + want_item["configured_password"], + ) + locald_params.append(want_item) + if want_item["group"] is not None: + locald_group_params.append(want_item) + if want_item["groups"] is not None: + for group in want_item["groups"]: + want_item["group"] = group + locald_group_params.append(want_item.copy()) + else: + if os_version and Version(os_version) > Version("7.0"): + if obj_in_have: + # Add iosxr 7.0 > specific parameters + want_item["type"] = "type5" + want_item["ordering_index"] = obj_in_have["ordering_index"] + if ( + self._module.params["update_password"] == "always" + and want_item["configured_password"] is not None + ): + + want_item["configured_password"] = self.generate_md5_hash( + want_item["configured_password"], + ) + locald_params.append(want_item) + else: + want_item["configured_password"] = None + + if ( + want_item["group"] is not None + and want_item["group"] != obj_in_have["group"] + ): + locald_group_params.append(want_item) + elif want_item["groups"] is not None: + for group in want_item["groups"]: + want_item["group"] = group + locald_group_params.append(want_item.copy()) + + purge_params = list() + if self._module.params["purge"]: + want_users = [x["name"] for x in self._want] + have_users = [x["name"] for x in self._have] + for item in set(have_users).difference(set(want_users)): + if item != "admin": + purge_params.append({"name": item}) + + self._result["xml"] = [] + _edit_filter_list = list() + if opcode is not None: + if locald_params: + _edit_filter_list.append( + build_xml("aaa", xmap=self._locald_meta, params=locald_params, opcode=opcode), + ) + + if locald_group_params: + _edit_filter_list.append( + build_xml( + "aaa", + xmap=self._locald_group_meta, + params=locald_group_params, + opcode=opcode, + ), + ) + + if purge_params: + _edit_filter_list.append( + build_xml("aaa", xmap=self._locald_meta, params=purge_params, opcode="delete"), + ) + diff = None + if _edit_filter_list: + commit = not self._module.check_mode + diff = load_config( + self._module, + _edit_filter_list, + commit=commit, + running=running, + nc_get_filter=_get_filter, + ) + + if diff: + if self._module._diff: + self._result["diff"] = dict(prepared=diff) + + self._result["xml"] = _edit_filter_list + self._result["changed"] = True + + def run(self): + os_version = get_capabilities(self._module).get("device_info").get("network_os_version") + self.map_params_to_obj() + self.map_obj_to_xml_rpc(os_version) + + return self._result + + +def main(): + """main entry point for module execution""" + element_spec = dict( + name=dict(type="str"), + configured_password=dict(type="str", no_log=True), + update_password=dict(type="str", default="always", choices=["on_create", "always"]), + admin=dict(type="bool", default=False), + public_key=dict(type="str"), + public_key_contents=dict(type="str"), + group=dict(type="str", aliases=["role"]), + groups=dict(type="list", elements="str"), + state=dict(type="str", default="present", choices=["present", "absent"]), + ) + aggregate_spec = deepcopy(element_spec) + aggregate_spec["name"] = dict(required=True) + + # remove default in aggregate spec, to handle common arguments + remove_default_spec(aggregate_spec) + + mutually_exclusive = [ + ("name", "aggregate"), + ("public_key", "public_key_contents"), + ("group", "groups"), + ] + + argument_spec = dict( + aggregate=dict( + type="list", + elements="dict", + options=aggregate_spec, + aliases=["users", "collection"], + ), + purge=dict(type="bool", default=False), + ) + + argument_spec.update(element_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + if module.params["public_key_contents"] or module.params["public_key"]: + if not HAS_B64: + module.fail_json( + msg="library base64 is required but does not appear to be " + "installed. It can be installed using `pip install base64`", + ) + + result = {"changed": False, "warnings": []} + + config_object = None + if is_cliconf(module): + # Commenting the below cliconf deprecation support call for Ansible 2.9 as it'll be continued to be supported + config_object = CliConfiguration(module, result) + elif is_netconf(module): + config_object = NCConfiguration(module, result) + + if config_object: + result = config_object.run() + + if module.params["public_key_contents"] or module.params["public_key"]: + pubkey_object = PublicKeyManager(module, result) + result = pubkey_object.run() + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cisco/iosxr/plugins/netconf/__init__.py b/ansible_collections/cisco/iosxr/plugins/netconf/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/netconf/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/netconf/iosxr.py b/ansible_collections/cisco/iosxr/plugins/netconf/iosxr.py new file mode 100644 index 00000000..e0b1bac8 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/netconf/iosxr.py @@ -0,0 +1,378 @@ +# +# (c) 2017 Red Hat Inc. +# (c) 2017 Kedar Kekan (kkekan@redhat.com) +# +# 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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +author: Ansible Networking Team (@ansible-network) +name: iosxr +short_description: Use iosxr netconf plugin to run netconf commands on Cisco IOSXR + platform +description: +- This iosxr plugin provides low level abstraction apis for sending and receiving + netconf commands from Cisco iosxr network devices. +version_added: 1.0.0 +options: + ncclient_device_handler: + type: str + default: iosxr + description: + - Specifies the ncclient device handler name for Cisco iosxr network os. To identify + the ncclient device handler name refer ncclient library documentation. +""" + +import collections +import json +import re + +from ansible.errors import AnsibleConnectionFailure +from ansible.module_utils._text import to_native, to_text +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import ( + remove_namespaces, +) +from ansible_collections.ansible.netcommon.plugins.plugin_utils.netconf_base import ( + NetconfBase, + ensure_ncclient, +) + +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( + build_xml, + etree_find, +) + + +try: + from ncclient import manager + from ncclient.operations import RPCError + from ncclient.transport.errors import SSHUnknownHostError + from ncclient.xml_ import to_xml + + HAS_NCCLIENT = True +except ( + ImportError, + AttributeError, +): # paramiko and gssapi are incompatible and raise AttributeError not ImportError + HAS_NCCLIENT = False + + +class Netconf(NetconfBase): + def get_device_info(self): + device_info = {} + device_info["network_os"] = "iosxr" + install_meta = collections.OrderedDict() + install_meta.update( + [ + ("prepare", {"xpath": "install/prepare", "tag": True}), + ( + "prepared-boot-image", + { + "xpath": "install/prepare/prepared-boot-image", + "tag": True, + }, + ), + ("version", {"xpath": "install/version", "tag": True}), + ("label", {"xpath": "install/version/label", "tag": True}), + ( + "hardware-info", + {"xpath": "install/version/hardware-info", "tag": True}, + ), + ("package", {"xpath": "install/version/package", "tag": True}), + ], + ) + install_filter = build_xml( + "install", + install_meta, + opcode="filter", + namespace="install", + ) + try: + reply = self.get(install_filter) + resp = remove_namespaces( + re.sub(r'<\?xml version="1.0" encoding="UTF-8"\?>', "", reply), + ) + ele_package_name = etree_find(resp.strip(), "name") + if ele_package_name is not None: + device_info["network_os_package"] = ele_package_name.text + ele_label = etree_find(resp.strip(), "label") + if ele_label is not None: + device_info["network_os_version"] = ele_label.text + + model_search_strs = [ + r"^[Cc]isco (.+) \(\) processor", + r"^[Cc]isco (.+) \(revision", + r"^[Cc]isco (\S+ \S+).+bytes of .*memory", + ] + ele_hardware_info = etree_find(resp.strip(), "hardware-info") + if ele_hardware_info is not None: + for item in model_search_strs: + match = re.search(item, ele_hardware_info.text, re.M) + if match: + device_info["network_os_model"] = match.group(1) + break + except Exception as exc: + error_msg = to_text(exc, errors="surrogate_or_strict").strip() + if "bad-namespace" in error_msg: + device_info = self.get_device_info_old_version() + else: + self._connection.queue_message( + "vvvv", + "Fail to retrieve device info %s" % exc, + ) + try: + hostname_filter = build_xml( + "host-names", + opcode="filter", + namespace="host-names", + ) + reply = self.get(hostname_filter) + resp = remove_namespaces( + re.sub(r'<\?xml version="1.0" encoding="UTF-8"\?>', "", reply), + ) + hostname_ele = etree_find(resp.strip(), "host-name") + device_info["network_os_hostname"] = ( + hostname_ele.text if hostname_ele is not None else None + ) + except Exception as exc: + self._connection.queue_message( + "vvvv", + "Fail to retrieve device info %s" % exc, + ) + return device_info + + def get_capabilities(self): + result = dict() + result["rpc"] = self.get_base_rpc() + result["network_api"] = "netconf" + result["device_info"] = self.get_device_info() + result["server_capabilities"] = list(self.m.server_capabilities) + result["client_capabilities"] = list(self.m.client_capabilities) + result["session_id"] = self.m.session_id + result["device_operations"] = self.get_device_operations( + result["server_capabilities"], + ) + return json.dumps(result) + + @staticmethod + @ensure_ncclient + def guess_network_os(obj): + """ + Guess the remote network os name + :param obj: Netconf connection class object + :return: Network OS name + """ + try: + m = manager.connect( + host=obj._play_context.remote_addr, + port=obj._play_context.port or 830, + username=obj._play_context.remote_user, + password=obj._play_context.password, + key_filename=obj.key_filename, + hostkey_verify=obj.get_option("host_key_checking"), + look_for_keys=obj.get_option("look_for_keys"), + allow_agent=obj._play_context.allow_agent, + timeout=obj.get_option("persistent_connect_timeout"), + # We need to pass in the path to the ssh_config file when guessing + # the network_os so that a jumphost is correctly used if defined + ssh_config=obj._ssh_config, + ) + except SSHUnknownHostError as exc: + raise AnsibleConnectionFailure(to_native(exc)) + + guessed_os = None + for c in m.server_capabilities: + if re.search("IOS-XR", c): + guessed_os = "iosxr" + break + + m.close_session() + return guessed_os + + # TODO: change .xml to .data_xml, when ncclient supports data_xml on all platforms + def get(self, filter=None, remove_ns=False): + if isinstance(filter, list): + filter = tuple(filter) + try: + resp = self.m.get(filter=filter) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def get_config(self, source=None, filter=None, remove_ns=False): + if isinstance(filter, list): + filter = tuple(filter) + try: + resp = self.m.get_config(source=source, filter=filter) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def edit_config( + self, + config=None, + format="xml", + target="candidate", + default_operation=None, + test_option=None, + error_option=None, + remove_ns=False, + ): + if config is None: + raise ValueError("config value must be provided") + try: + resp = self.m.edit_config( + config, + format=format, + target=target, + default_operation=default_operation, + test_option=test_option, + error_option=error_option, + ) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def commit( + self, + confirmed=False, + timeout=None, + persist=None, + remove_ns=False, + ): + timeout = to_text(timeout, errors="surrogate_or_strict") + try: + resp = self.m.commit( + confirmed=confirmed, + timeout=timeout, + persist=persist, + ) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def validate(self, source="candidate", remove_ns=False): + try: + resp = self.m.validate(source=source) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def discard_changes(self, remove_ns=False): + try: + resp = self.m.discard_changes() + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, "data_xml") else resp.xml + return response + except RPCError as exc: + raise Exception(to_xml(exc.xml)) + + def get_device_info_old_version(self): + device_info = {} + device_info["network_os"] = "iosxr" + install_meta = collections.OrderedDict() + install_meta.update( + [ + ( + "boot-variables", + {"xpath": "install/boot-variables", "tag": True}, + ), + ( + "boot-variable", + { + "xpath": "install/boot-variables/boot-variable", + "tag": True, + "lead": True, + }, + ), + ("software", {"xpath": "install/software", "tag": True}), + ( + "alias-devices", + {"xpath": "install/software/alias-devices", "tag": True}, + ), + ( + "alias-device", + { + "xpath": "install/software/alias-devices/alias-device", + "tag": True, + }, + ), + ( + "m:device-name", + { + "xpath": "install/software/alias-devices/alias-device/device-name", + "value": "disk0:", + }, + ), + ], + ) + + install_filter = build_xml( + "install", + install_meta, + opcode="filter", + namespace="install_old", + ) + try: + reply = self.get(install_filter) + resp = remove_namespaces( + re.sub(r'<\?xml version="1.0" encoding="UTF-8"\?>', "", reply), + ) + ele_boot_variable = etree_find(resp, "boot-variable/boot-variable") + if ele_boot_variable is not None: + device_info["network_os_image"] = re.split( + "[:|,]", + ele_boot_variable.text, + )[1] + ele_package_name = etree_find(reply, "package-name") + if ele_package_name is not None: + device_info["network_os_package"] = ele_package_name.text + device_info["network_os_version"] = re.split( + "-", + ele_package_name.text, + )[-1] + except Exception as exc: + self._connection.queue_message( + "vvvv", + "Fail to retrieve device info %s" % exc, + ) + return device_info diff --git a/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/__init__.py b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/iosxr.py b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/iosxr.py new file mode 100644 index 00000000..0bcfd0e7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/iosxr.py @@ -0,0 +1,200 @@ +# (c) 2019 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +--- +author: Ansible Networking Team +grpc : iosxr +short_description: gRPC Plugin for IOS XR devices +description: + - This gRPC plugin provides methods to connect and talk to Cisco IOS XR + devices over gRPC protocol. +version_added: "" +""" +import json +import os +import sys + +from ansible_collections.ansible.netcommon.plugins.sub_plugins.grpc.base import ( + GrpcBase, + ensure_connect, +) + + +class Grpc(GrpcBase): + def __init__(self, connection): + super(Grpc, self).__init__(connection) + module_name = "ems_grpc_pb2" + module_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "pb/ems_grpc_pb2.py", + ) + if sys.version_info[0] == 3 and sys.version_info[1] >= 5: + import importlib.util + + spec = importlib.util.spec_from_file_location(module_name, module_path) + self._ems_grpc_pb2 = importlib.util.module_from_spec(spec) + spec.loader.exec_module(self._ems_grpc_pb2) + elif sys.version_info[0] == 3 and sys.version_info[1] < 5: + import importlib.machinery + + loader = importlib.machinery.SourceFileLoader(module_name, module_path) + self._ems_grpc_pb2 = loader.load_module() + elif sys.version_info[0] == 2: + import imp + + self._ems_grpc_pb2 = imp.load_source(module_name, module_path) + + def get_config(self, section=None): + stub = self._ems_grpc_pb2.beta_create_gRPCConfigOper_stub( + self._connection._channel, + ) + message = self._ems_grpc_pb2.ConfigGetArgs(yangpathjson=section) + responses = stub.GetConfig( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + output = {"response": "", "error": ""} + for response in responses: + output["response"] += response.yangjson + output["error"] += response.errors + return output + + def get(self, section=None): + stub = self._ems_grpc_pb2.beta_create_gRPCConfigOper_stub( + self._connection._channel, + ) + message = self._ems_grpc_pb2.GetOperArgs(yangpathjson=section) + responses = stub.GetOper( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + output = {"response": "", "error": ""} + for response in responses: + output["response"] += response.yangjson + output["error"] += response.errors + return output + + @ensure_connect + def merge_config(self, path): + """Merge grpc call equivalent of PATCH RESTconf call + :param data: JSON + :type data: str + :return: Return the response object + :rtype: Response object + """ + path = json.dumps(path) + stub = self._ems_grpc_pb2.beta_create_gRPCConfigOper_stub( + self._connection._channel, + ) + message = self._ems_grpc_pb2.ConfigArgs(yangjson=path) + response = stub.MergeConfig( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + if response: + return response.errors + else: + return None + + @ensure_connect + def replace_config(self, path): + """Replace grpc call equivalent of PATCH RESTconf call + :param data: JSON + :type data: str + :return: Return the response object + :rtype: Response object + """ + path = json.dumps(path) + stub = self._ems_grpc_pb2.beta_create_gRPCConfigOper_stub( + self._connection._channel, + ) + message = self._ems_grpc_pb2.ConfigArgs(yangjson=path) + response = stub.ReplaceConfig( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + if response: + return response.errors + else: + return None + + @ensure_connect + def delete_config(self, path): + """Delete grpc call equivalent of PATCH RESTconf call + :param data: JSON + :type data: str + :return: Return the response object + :rtype: Response object + """ + path = json.dumps(path) + stub = self._ems_grpc_pb2.beta_create_gRPCConfigOper_stub( + self._connection._channel, + ) + message = self._ems_grpc_pb2.ConfigArgs(yangjson=path) + response = stub.DeleteConfig( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + if response: + return response.errors + else: + return None + + @ensure_connect + def run_cli(self, command=None, display=None): + if command is None: + raise ValueError("command value must be provided") + + output = {"response": "", "error": ""} + stub = self._ems_grpc_pb2.beta_create_gRPCExec_stub( + self._connection._channel, + ) + + message = self._ems_grpc_pb2.ShowCmdArgs(cli=command) + if display == "text": + responses = stub.ShowCmdTextOutput( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + for response in responses: + output["response"] += response.output + output["error"] += response.errors + else: + responses = stub.ShowCmdJSONOutput( + message, + self._connection._timeout, + metadata=self._connection._login_credentials, + ) + for response in responses: + output["response"] += response.jsonoutput + output["error"] += response.errors + return output + + @property + def server_capabilities(self): + capability = dict() + capability["display"] = ["json", "text"] + capability["data_type"] = ["config", "oper"] + capability["supports_commit"] = True + capability["supports_cli_command"] = True + return capability + + @ensure_connect + def get_capabilities(self): + result = dict() + result["rpc"] = self.__rpc__ + ["commit", "discard_changes"] + result["network_api"] = "ansible.netcommon.grpc" + result["server_capabilities"] = self.server_capabilities + return result diff --git a/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/__init__.py b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/ems_grpc_pb2.py b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/ems_grpc_pb2.py new file mode 100644 index 00000000..e16c305b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/sub_plugins/grpc/pb/ems_grpc_pb2.py @@ -0,0 +1,2350 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: ems_grpc.proto +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import sys + + +_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode("latin1")) +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pb2 # noqa: F401 +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import enum_type_wrapper + + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor.FileDescriptor( + name="ems_grpc.proto", + package="IOSXRExtensibleManagabilityService", + syntax="proto3", + serialized_pb=_b( + '\n\x0e\x65ms_grpc.proto\x12"IOSXRExtensibleManagabilityService"4\n\rConfigGetArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x14\n\x0cyangpathjson\x18\x02 \x01(\t"D\n\x0e\x43onfigGetReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x10\n\x08yangjson\x18\x02 \x01(\t\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t"2\n\x0bGetOperArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x14\n\x0cyangpathjson\x18\x02 \x01(\t"B\n\x0cGetOperReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x10\n\x08yangjson\x18\x02 \x01(\t\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t"-\n\nConfigArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x10\n\x08yangjson\x18\x02 \x01(\t"/\n\x0b\x43onfigReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t"+\n\rCliConfigArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x0b\n\x03\x63li\x18\x02 \x01(\t"2\n\x0e\x43liConfigReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t"A\n\x11\x43ommitReplaceArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x0b\n\x03\x63li\x18\x02 \x01(\t\x12\x10\n\x08yangjson\x18\x03 \x01(\t"6\n\x12\x43ommitReplaceReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t"+\n\tCommitMsg\x12\r\n\x05label\x18\x01 \x01(\t\x12\x0f\n\x07\x63omment\x18\x02 \x01(\t"W\n\nCommitArgs\x12:\n\x03msg\x18\x01 \x01(\x0b\x32-.IOSXRExtensibleManagabilityService.CommitMsg\x12\r\n\x05ReqId\x18\x02 \x01(\x03"q\n\x0b\x43ommitReply\x12@\n\x06result\x18\x01 \x01(\x0e\x32\x30.IOSXRExtensibleManagabilityService.CommitResult\x12\x10\n\x08ResReqId\x18\x02 \x01(\x03\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t"#\n\x12\x44iscardChangesArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03"7\n\x13\x44iscardChangesReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0e\n\x06\x65rrors\x18\x02 \x01(\t")\n\x0bShowCmdArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x0b\n\x03\x63li\x18\x02 \x01(\t"D\n\x10ShowCmdTextReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0e\n\x06output\x18\x02 \x01(\t\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t"H\n\x10ShowCmdJSONReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x12\n\njsonoutput\x18\x02 \x01(\t\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t"A\n\x0e\x43reateSubsArgs\x12\r\n\x05ReqId\x18\x01 \x01(\x03\x12\x0e\n\x06\x65ncode\x18\x02 \x01(\x03\x12\x10\n\x08subidstr\x18\x03 \x01(\t"A\n\x0f\x43reateSubsReply\x12\x10\n\x08ResReqId\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0e\n\x06\x65rrors\x18\x03 \x01(\t*3\n\x0c\x43ommitResult\x12\n\n\x06\x43HANGE\x10\x00\x12\r\n\tNO_CHANGE\x10\x01\x12\x08\n\x04\x46\x41IL\x10\x02\x32\xc6\t\n\x0egRPCConfigOper\x12v\n\tGetConfig\x12\x31.IOSXRExtensibleManagabilityService.ConfigGetArgs\x1a\x32.IOSXRExtensibleManagabilityService.ConfigGetReply"\x00\x30\x01\x12p\n\x0bMergeConfig\x12..IOSXRExtensibleManagabilityService.ConfigArgs\x1a/.IOSXRExtensibleManagabilityService.ConfigReply"\x00\x12q\n\x0c\x44\x65leteConfig\x12..IOSXRExtensibleManagabilityService.ConfigArgs\x1a/.IOSXRExtensibleManagabilityService.ConfigReply"\x00\x12r\n\rReplaceConfig\x12..IOSXRExtensibleManagabilityService.ConfigArgs\x1a/.IOSXRExtensibleManagabilityService.ConfigReply"\x00\x12t\n\tCliConfig\x12\x31.IOSXRExtensibleManagabilityService.CliConfigArgs\x1a\x32.IOSXRExtensibleManagabilityService.CliConfigReply"\x00\x12\x80\x01\n\rCommitReplace\x12\x35.IOSXRExtensibleManagabilityService.CommitReplaceArgs\x1a\x36.IOSXRExtensibleManagabilityService.CommitReplaceReply"\x00\x12q\n\x0c\x43ommitConfig\x12..IOSXRExtensibleManagabilityService.CommitArgs\x1a/.IOSXRExtensibleManagabilityService.CommitReply"\x00\x12\x89\x01\n\x14\x43onfigDiscardChanges\x12\x36.IOSXRExtensibleManagabilityService.DiscardChangesArgs\x1a\x37.IOSXRExtensibleManagabilityService.DiscardChangesReply"\x00\x12p\n\x07GetOper\x12/.IOSXRExtensibleManagabilityService.GetOperArgs\x1a\x30.IOSXRExtensibleManagabilityService.GetOperReply"\x00\x30\x01\x12y\n\nCreateSubs\x12\x32.IOSXRExtensibleManagabilityService.CreateSubsArgs\x1a\x33.IOSXRExtensibleManagabilityService.CreateSubsReply"\x00\x30\x01\x32\x8a\x02\n\x08gRPCExec\x12~\n\x11ShowCmdTextOutput\x12/.IOSXRExtensibleManagabilityService.ShowCmdArgs\x1a\x34.IOSXRExtensibleManagabilityService.ShowCmdTextReply"\x00\x30\x01\x12~\n\x11ShowCmdJSONOutput\x12/.IOSXRExtensibleManagabilityService.ShowCmdArgs\x1a\x34.IOSXRExtensibleManagabilityService.ShowCmdJSONReply"\x00\x30\x01\x62\x06proto3', # noqa: E501 + ), +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +_COMMITRESULT = _descriptor.EnumDescriptor( + name="CommitResult", + full_name="IOSXRExtensibleManagabilityService.CommitResult", + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name="CHANGE", + index=0, + number=0, + options=None, + type=None, + ), + _descriptor.EnumValueDescriptor( + name="NO_CHANGE", + index=1, + number=1, + options=None, + type=None, + ), + _descriptor.EnumValueDescriptor( + name="FAIL", + index=2, + number=2, + options=None, + type=None, + ), + ], + containing_type=None, + options=None, + serialized_start=1278, + serialized_end=1329, +) +_sym_db.RegisterEnumDescriptor(_COMMITRESULT) + +CommitResult = enum_type_wrapper.EnumTypeWrapper(_COMMITRESULT) +CHANGE = 0 +NO_CHANGE = 1 +FAIL = 2 + + +_CONFIGGETARGS = _descriptor.Descriptor( + name="ConfigGetArgs", + full_name="IOSXRExtensibleManagabilityService.ConfigGetArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.ConfigGetArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangpathjson", + full_name="IOSXRExtensibleManagabilityService.ConfigGetArgs.yangpathjson", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=54, + serialized_end=106, +) + + +_CONFIGGETREPLY = _descriptor.Descriptor( + name="ConfigGetReply", + full_name="IOSXRExtensibleManagabilityService.ConfigGetReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.ConfigGetReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangjson", + full_name="IOSXRExtensibleManagabilityService.ConfigGetReply.yangjson", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.ConfigGetReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=108, + serialized_end=176, +) + + +_GETOPERARGS = _descriptor.Descriptor( + name="GetOperArgs", + full_name="IOSXRExtensibleManagabilityService.GetOperArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.GetOperArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangpathjson", + full_name="IOSXRExtensibleManagabilityService.GetOperArgs.yangpathjson", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=178, + serialized_end=228, +) + + +_GETOPERREPLY = _descriptor.Descriptor( + name="GetOperReply", + full_name="IOSXRExtensibleManagabilityService.GetOperReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.GetOperReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangjson", + full_name="IOSXRExtensibleManagabilityService.GetOperReply.yangjson", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.GetOperReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=230, + serialized_end=296, +) + + +_CONFIGARGS = _descriptor.Descriptor( + name="ConfigArgs", + full_name="IOSXRExtensibleManagabilityService.ConfigArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.ConfigArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangjson", + full_name="IOSXRExtensibleManagabilityService.ConfigArgs.yangjson", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=298, + serialized_end=343, +) + + +_CONFIGREPLY = _descriptor.Descriptor( + name="ConfigReply", + full_name="IOSXRExtensibleManagabilityService.ConfigReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.ConfigReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.ConfigReply.errors", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=345, + serialized_end=392, +) + + +_CLICONFIGARGS = _descriptor.Descriptor( + name="CliConfigArgs", + full_name="IOSXRExtensibleManagabilityService.CliConfigArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.CliConfigArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="cli", + full_name="IOSXRExtensibleManagabilityService.CliConfigArgs.cli", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=394, + serialized_end=437, +) + + +_CLICONFIGREPLY = _descriptor.Descriptor( + name="CliConfigReply", + full_name="IOSXRExtensibleManagabilityService.CliConfigReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.CliConfigReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.CliConfigReply.errors", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=439, + serialized_end=489, +) + + +_COMMITREPLACEARGS = _descriptor.Descriptor( + name="CommitReplaceArgs", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="cli", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceArgs.cli", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="yangjson", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceArgs.yangjson", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=491, + serialized_end=556, +) + + +_COMMITREPLACEREPLY = _descriptor.Descriptor( + name="CommitReplaceReply", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.CommitReplaceReply.errors", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=558, + serialized_end=612, +) + + +_COMMITMSG = _descriptor.Descriptor( + name="CommitMsg", + full_name="IOSXRExtensibleManagabilityService.CommitMsg", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="label", + full_name="IOSXRExtensibleManagabilityService.CommitMsg.label", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="comment", + full_name="IOSXRExtensibleManagabilityService.CommitMsg.comment", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=614, + serialized_end=657, +) + + +_COMMITARGS = _descriptor.Descriptor( + name="CommitArgs", + full_name="IOSXRExtensibleManagabilityService.CommitArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="msg", + full_name="IOSXRExtensibleManagabilityService.CommitArgs.msg", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.CommitArgs.ReqId", + index=1, + number=2, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=659, + serialized_end=746, +) + + +_COMMITREPLY = _descriptor.Descriptor( + name="CommitReply", + full_name="IOSXRExtensibleManagabilityService.CommitReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="result", + full_name="IOSXRExtensibleManagabilityService.CommitReply.result", + index=0, + number=1, + type=14, + cpp_type=8, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.CommitReply.ResReqId", + index=1, + number=2, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.CommitReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=748, + serialized_end=861, +) + + +_DISCARDCHANGESARGS = _descriptor.Descriptor( + name="DiscardChangesArgs", + full_name="IOSXRExtensibleManagabilityService.DiscardChangesArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.DiscardChangesArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=863, + serialized_end=898, +) + + +_DISCARDCHANGESREPLY = _descriptor.Descriptor( + name="DiscardChangesReply", + full_name="IOSXRExtensibleManagabilityService.DiscardChangesReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.DiscardChangesReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.DiscardChangesReply.errors", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=900, + serialized_end=955, +) + + +_SHOWCMDARGS = _descriptor.Descriptor( + name="ShowCmdArgs", + full_name="IOSXRExtensibleManagabilityService.ShowCmdArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.ShowCmdArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="cli", + full_name="IOSXRExtensibleManagabilityService.ShowCmdArgs.cli", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=957, + serialized_end=998, +) + + +_SHOWCMDTEXTREPLY = _descriptor.Descriptor( + name="ShowCmdTextReply", + full_name="IOSXRExtensibleManagabilityService.ShowCmdTextReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.ShowCmdTextReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="output", + full_name="IOSXRExtensibleManagabilityService.ShowCmdTextReply.output", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.ShowCmdTextReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1000, + serialized_end=1068, +) + + +_SHOWCMDJSONREPLY = _descriptor.Descriptor( + name="ShowCmdJSONReply", + full_name="IOSXRExtensibleManagabilityService.ShowCmdJSONReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.ShowCmdJSONReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="jsonoutput", + full_name="IOSXRExtensibleManagabilityService.ShowCmdJSONReply.jsonoutput", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.ShowCmdJSONReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1070, + serialized_end=1142, +) + + +_CREATESUBSARGS = _descriptor.Descriptor( + name="CreateSubsArgs", + full_name="IOSXRExtensibleManagabilityService.CreateSubsArgs", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ReqId", + full_name="IOSXRExtensibleManagabilityService.CreateSubsArgs.ReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="encode", + full_name="IOSXRExtensibleManagabilityService.CreateSubsArgs.encode", + index=1, + number=2, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="subidstr", + full_name="IOSXRExtensibleManagabilityService.CreateSubsArgs.subidstr", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1144, + serialized_end=1209, +) + + +_CREATESUBSREPLY = _descriptor.Descriptor( + name="CreateSubsReply", + full_name="IOSXRExtensibleManagabilityService.CreateSubsReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="ResReqId", + full_name="IOSXRExtensibleManagabilityService.CreateSubsReply.ResReqId", + index=0, + number=1, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="data", + full_name="IOSXRExtensibleManagabilityService.CreateSubsReply.data", + index=1, + number=2, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + _descriptor.FieldDescriptor( + name="errors", + full_name="IOSXRExtensibleManagabilityService.CreateSubsReply.errors", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + options=None, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1211, + serialized_end=1276, +) + +_COMMITARGS.fields_by_name["msg"].message_type = _COMMITMSG +_COMMITREPLY.fields_by_name["result"].enum_type = _COMMITRESULT +DESCRIPTOR.message_types_by_name["ConfigGetArgs"] = _CONFIGGETARGS +DESCRIPTOR.message_types_by_name["ConfigGetReply"] = _CONFIGGETREPLY +DESCRIPTOR.message_types_by_name["GetOperArgs"] = _GETOPERARGS +DESCRIPTOR.message_types_by_name["GetOperReply"] = _GETOPERREPLY +DESCRIPTOR.message_types_by_name["ConfigArgs"] = _CONFIGARGS +DESCRIPTOR.message_types_by_name["ConfigReply"] = _CONFIGREPLY +DESCRIPTOR.message_types_by_name["CliConfigArgs"] = _CLICONFIGARGS +DESCRIPTOR.message_types_by_name["CliConfigReply"] = _CLICONFIGREPLY +DESCRIPTOR.message_types_by_name["CommitReplaceArgs"] = _COMMITREPLACEARGS +DESCRIPTOR.message_types_by_name["CommitReplaceReply"] = _COMMITREPLACEREPLY +DESCRIPTOR.message_types_by_name["CommitMsg"] = _COMMITMSG +DESCRIPTOR.message_types_by_name["CommitArgs"] = _COMMITARGS +DESCRIPTOR.message_types_by_name["CommitReply"] = _COMMITREPLY +DESCRIPTOR.message_types_by_name["DiscardChangesArgs"] = _DISCARDCHANGESARGS +DESCRIPTOR.message_types_by_name["DiscardChangesReply"] = _DISCARDCHANGESREPLY +DESCRIPTOR.message_types_by_name["ShowCmdArgs"] = _SHOWCMDARGS +DESCRIPTOR.message_types_by_name["ShowCmdTextReply"] = _SHOWCMDTEXTREPLY +DESCRIPTOR.message_types_by_name["ShowCmdJSONReply"] = _SHOWCMDJSONREPLY +DESCRIPTOR.message_types_by_name["CreateSubsArgs"] = _CREATESUBSARGS +DESCRIPTOR.message_types_by_name["CreateSubsReply"] = _CREATESUBSREPLY +DESCRIPTOR.enum_types_by_name["CommitResult"] = _COMMITRESULT + +ConfigGetArgs = _reflection.GeneratedProtocolMessageType( + "ConfigGetArgs", + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGGETARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ConfigGetArgs) + ), +) +_sym_db.RegisterMessage(ConfigGetArgs) + +ConfigGetReply = _reflection.GeneratedProtocolMessageType( + "ConfigGetReply", + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGGETREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ConfigGetReply) + ), +) +_sym_db.RegisterMessage(ConfigGetReply) + +GetOperArgs = _reflection.GeneratedProtocolMessageType( + "GetOperArgs", + (_message.Message,), + dict( + DESCRIPTOR=_GETOPERARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.GetOperArgs) + ), +) +_sym_db.RegisterMessage(GetOperArgs) + +GetOperReply = _reflection.GeneratedProtocolMessageType( + "GetOperReply", + (_message.Message,), + dict( + DESCRIPTOR=_GETOPERREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.GetOperReply) + ), +) +_sym_db.RegisterMessage(GetOperReply) + +ConfigArgs = _reflection.GeneratedProtocolMessageType( + "ConfigArgs", + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ConfigArgs) + ), +) +_sym_db.RegisterMessage(ConfigArgs) + +ConfigReply = _reflection.GeneratedProtocolMessageType( + "ConfigReply", + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ConfigReply) + ), +) +_sym_db.RegisterMessage(ConfigReply) + +CliConfigArgs = _reflection.GeneratedProtocolMessageType( + "CliConfigArgs", + (_message.Message,), + dict( + DESCRIPTOR=_CLICONFIGARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CliConfigArgs) + ), +) +_sym_db.RegisterMessage(CliConfigArgs) + +CliConfigReply = _reflection.GeneratedProtocolMessageType( + "CliConfigReply", + (_message.Message,), + dict( + DESCRIPTOR=_CLICONFIGREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CliConfigReply) + ), +) +_sym_db.RegisterMessage(CliConfigReply) + +CommitReplaceArgs = _reflection.GeneratedProtocolMessageType( + "CommitReplaceArgs", + (_message.Message,), + dict( + DESCRIPTOR=_COMMITREPLACEARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CommitReplaceArgs) + ), +) +_sym_db.RegisterMessage(CommitReplaceArgs) + +CommitReplaceReply = _reflection.GeneratedProtocolMessageType( + "CommitReplaceReply", + (_message.Message,), + dict( + DESCRIPTOR=_COMMITREPLACEREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CommitReplaceReply) + ), +) +_sym_db.RegisterMessage(CommitReplaceReply) + +CommitMsg = _reflection.GeneratedProtocolMessageType( + "CommitMsg", + (_message.Message,), + dict( + DESCRIPTOR=_COMMITMSG, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CommitMsg) + ), +) +_sym_db.RegisterMessage(CommitMsg) + +CommitArgs = _reflection.GeneratedProtocolMessageType( + "CommitArgs", + (_message.Message,), + dict( + DESCRIPTOR=_COMMITARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CommitArgs) + ), +) +_sym_db.RegisterMessage(CommitArgs) + +CommitReply = _reflection.GeneratedProtocolMessageType( + "CommitReply", + (_message.Message,), + dict( + DESCRIPTOR=_COMMITREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CommitReply) + ), +) +_sym_db.RegisterMessage(CommitReply) + +DiscardChangesArgs = _reflection.GeneratedProtocolMessageType( + "DiscardChangesArgs", + (_message.Message,), + dict( + DESCRIPTOR=_DISCARDCHANGESARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.DiscardChangesArgs) + ), +) +_sym_db.RegisterMessage(DiscardChangesArgs) + +DiscardChangesReply = _reflection.GeneratedProtocolMessageType( + "DiscardChangesReply", + (_message.Message,), + dict( + DESCRIPTOR=_DISCARDCHANGESREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.DiscardChangesReply) + ), +) +_sym_db.RegisterMessage(DiscardChangesReply) + +ShowCmdArgs = _reflection.GeneratedProtocolMessageType( + "ShowCmdArgs", + (_message.Message,), + dict( + DESCRIPTOR=_SHOWCMDARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ShowCmdArgs) + ), +) +_sym_db.RegisterMessage(ShowCmdArgs) + +ShowCmdTextReply = _reflection.GeneratedProtocolMessageType( + "ShowCmdTextReply", + (_message.Message,), + dict( + DESCRIPTOR=_SHOWCMDTEXTREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ShowCmdTextReply) + ), +) +_sym_db.RegisterMessage(ShowCmdTextReply) + +ShowCmdJSONReply = _reflection.GeneratedProtocolMessageType( + "ShowCmdJSONReply", + (_message.Message,), + dict( + DESCRIPTOR=_SHOWCMDJSONREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.ShowCmdJSONReply) + ), +) +_sym_db.RegisterMessage(ShowCmdJSONReply) + +CreateSubsArgs = _reflection.GeneratedProtocolMessageType( + "CreateSubsArgs", + (_message.Message,), + dict( + DESCRIPTOR=_CREATESUBSARGS, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CreateSubsArgs) + ), +) +_sym_db.RegisterMessage(CreateSubsArgs) + +CreateSubsReply = _reflection.GeneratedProtocolMessageType( + "CreateSubsReply", + (_message.Message,), + dict( + DESCRIPTOR=_CREATESUBSREPLY, + __module__="ems_grpc_pb2", + # @@protoc_insertion_point(class_scope:IOSXRExtensibleManagabilityService.CreateSubsReply) + ), +) +_sym_db.RegisterMessage(CreateSubsReply) + + +import grpc + +from grpc.beta import implementations as beta_implementations +from grpc.beta import interfaces as beta_interfaces +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities + + +class gRPCConfigOperStub(object): + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetConfig = channel.unary_stream( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/GetConfig", + request_serializer=ConfigGetArgs.SerializeToString, + response_deserializer=ConfigGetReply.FromString, + ) + self.MergeConfig = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/MergeConfig", + request_serializer=ConfigArgs.SerializeToString, + response_deserializer=ConfigReply.FromString, + ) + self.DeleteConfig = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/DeleteConfig", + request_serializer=ConfigArgs.SerializeToString, + response_deserializer=ConfigReply.FromString, + ) + self.ReplaceConfig = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/ReplaceConfig", + request_serializer=ConfigArgs.SerializeToString, + response_deserializer=ConfigReply.FromString, + ) + self.CliConfig = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/CliConfig", + request_serializer=CliConfigArgs.SerializeToString, + response_deserializer=CliConfigReply.FromString, + ) + self.CommitReplace = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/CommitReplace", + request_serializer=CommitReplaceArgs.SerializeToString, + response_deserializer=CommitReplaceReply.FromString, + ) + self.CommitConfig = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/CommitConfig", + request_serializer=CommitArgs.SerializeToString, + response_deserializer=CommitReply.FromString, + ) + self.ConfigDiscardChanges = channel.unary_unary( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/ConfigDiscardChanges", + request_serializer=DiscardChangesArgs.SerializeToString, + response_deserializer=DiscardChangesReply.FromString, + ) + self.GetOper = channel.unary_stream( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/GetOper", + request_serializer=GetOperArgs.SerializeToString, + response_deserializer=GetOperReply.FromString, + ) + self.CreateSubs = channel.unary_stream( + "/IOSXRExtensibleManagabilityService.gRPCConfigOper/CreateSubs", + request_serializer=CreateSubsArgs.SerializeToString, + response_deserializer=CreateSubsReply.FromString, + ) + + +class gRPCConfigOperServicer(object): + def GetConfig(self, request, context): + """Configuration related commands""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def MergeConfig(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def DeleteConfig(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ReplaceConfig(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CliConfig(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CommitReplace(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CommitConfig(self, request, context): + """Do we need implicit or explicit commit""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ConfigDiscardChanges(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetOper(self, request, context): + """Get only returns oper data""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CreateSubs(self, request, context): + """Get Telemetry Data""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_gRPCConfigOperServicer_to_server(servicer, server): + rpc_method_handlers = { + "GetConfig": grpc.unary_stream_rpc_method_handler( + servicer.GetConfig, + request_deserializer=ConfigGetArgs.FromString, + response_serializer=ConfigGetReply.SerializeToString, + ), + "MergeConfig": grpc.unary_unary_rpc_method_handler( + servicer.MergeConfig, + request_deserializer=ConfigArgs.FromString, + response_serializer=ConfigReply.SerializeToString, + ), + "DeleteConfig": grpc.unary_unary_rpc_method_handler( + servicer.DeleteConfig, + request_deserializer=ConfigArgs.FromString, + response_serializer=ConfigReply.SerializeToString, + ), + "ReplaceConfig": grpc.unary_unary_rpc_method_handler( + servicer.ReplaceConfig, + request_deserializer=ConfigArgs.FromString, + response_serializer=ConfigReply.SerializeToString, + ), + "CliConfig": grpc.unary_unary_rpc_method_handler( + servicer.CliConfig, + request_deserializer=CliConfigArgs.FromString, + response_serializer=CliConfigReply.SerializeToString, + ), + "CommitReplace": grpc.unary_unary_rpc_method_handler( + servicer.CommitReplace, + request_deserializer=CommitReplaceArgs.FromString, + response_serializer=CommitReplaceReply.SerializeToString, + ), + "CommitConfig": grpc.unary_unary_rpc_method_handler( + servicer.CommitConfig, + request_deserializer=CommitArgs.FromString, + response_serializer=CommitReply.SerializeToString, + ), + "ConfigDiscardChanges": grpc.unary_unary_rpc_method_handler( + servicer.ConfigDiscardChanges, + request_deserializer=DiscardChangesArgs.FromString, + response_serializer=DiscardChangesReply.SerializeToString, + ), + "GetOper": grpc.unary_stream_rpc_method_handler( + servicer.GetOper, + request_deserializer=GetOperArgs.FromString, + response_serializer=GetOperReply.SerializeToString, + ), + "CreateSubs": grpc.unary_stream_rpc_method_handler( + servicer.CreateSubs, + request_deserializer=CreateSubsArgs.FromString, + response_serializer=CreateSubsReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + rpc_method_handlers, + ) + server.add_generic_rpc_handlers((generic_handler,)) + + +class BetagRPCConfigOperServicer(object): + def GetConfig(self, request, context): + """Configuration related commands""" + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def MergeConfig(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def DeleteConfig(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def ReplaceConfig(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def CliConfig(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def CommitReplace(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def CommitConfig(self, request, context): + """Do we need implicit or explicit commit""" + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def ConfigDiscardChanges(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def GetOper(self, request, context): + """Get only returns oper data""" + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def CreateSubs(self, request, context): + """Get Telemetry Data""" + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + +class BetagRPCConfigOperStub(object): + def GetConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + """Configuration related commands""" + raise NotImplementedError() + + def MergeConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + MergeConfig.future = None + + def DeleteConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + DeleteConfig.future = None + + def ReplaceConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + ReplaceConfig.future = None + + def CliConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + CliConfig.future = None + + def CommitReplace( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + CommitReplace.future = None + + def CommitConfig( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + """Do we need implicit or explicit commit""" + raise NotImplementedError() + + CommitConfig.future = None + + def ConfigDiscardChanges( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + ConfigDiscardChanges.future = None + + def GetOper( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + """Get only returns oper data""" + raise NotImplementedError() + + def CreateSubs( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + """Get Telemetry Data""" + raise NotImplementedError() + + +def beta_create_gRPCConfigOper_server( + servicer, + pool=None, + pool_size=None, + default_timeout=None, + maximum_timeout=None, +): + request_deserializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CliConfig", + ): CliConfigArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitConfig", + ): CommitArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitReplace", + ): CommitReplaceArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ConfigDiscardChanges", + ): DiscardChangesArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CreateSubs", + ): CreateSubsArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "DeleteConfig", + ): ConfigArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetConfig", + ): ConfigGetArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetOper", + ): GetOperArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "MergeConfig", + ): ConfigArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ReplaceConfig", + ): ConfigArgs.FromString, + } + response_serializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CliConfig", + ): CliConfigReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitConfig", + ): CommitReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitReplace", + ): CommitReplaceReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ConfigDiscardChanges", + ): DiscardChangesReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CreateSubs", + ): CreateSubsReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "DeleteConfig", + ): ConfigReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetConfig", + ): ConfigGetReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetOper", + ): GetOperReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "MergeConfig", + ): ConfigReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ReplaceConfig", + ): ConfigReply.SerializeToString, + } + method_implementations = { + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CliConfig", + ): face_utilities.unary_unary_inline(servicer.CliConfig), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitConfig", + ): face_utilities.unary_unary_inline(servicer.CommitConfig), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitReplace", + ): face_utilities.unary_unary_inline(servicer.CommitReplace), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ConfigDiscardChanges", + ): face_utilities.unary_unary_inline(servicer.ConfigDiscardChanges), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CreateSubs", + ): face_utilities.unary_stream_inline(servicer.CreateSubs), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "DeleteConfig", + ): face_utilities.unary_unary_inline(servicer.DeleteConfig), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetConfig", + ): face_utilities.unary_stream_inline(servicer.GetConfig), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetOper", + ): face_utilities.unary_stream_inline(servicer.GetOper), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "MergeConfig", + ): face_utilities.unary_unary_inline(servicer.MergeConfig), + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ReplaceConfig", + ): face_utilities.unary_unary_inline(servicer.ReplaceConfig), + } + server_options = beta_implementations.server_options( + request_deserializers=request_deserializers, + response_serializers=response_serializers, + thread_pool=pool, + thread_pool_size=pool_size, + default_timeout=default_timeout, + maximum_timeout=maximum_timeout, + ) + return beta_implementations.server( + method_implementations, + options=server_options, + ) + + +def beta_create_gRPCConfigOper_stub( + channel, + host=None, + metadata_transformer=None, + pool=None, + pool_size=None, +): + request_serializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CliConfig", + ): CliConfigArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitConfig", + ): CommitArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitReplace", + ): CommitReplaceArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ConfigDiscardChanges", + ): DiscardChangesArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CreateSubs", + ): CreateSubsArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "DeleteConfig", + ): ConfigArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetConfig", + ): ConfigGetArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetOper", + ): GetOperArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "MergeConfig", + ): ConfigArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ReplaceConfig", + ): ConfigArgs.SerializeToString, + } + response_deserializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CliConfig", + ): CliConfigReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitConfig", + ): CommitReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CommitReplace", + ): CommitReplaceReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ConfigDiscardChanges", + ): DiscardChangesReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "CreateSubs", + ): CreateSubsReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "DeleteConfig", + ): ConfigReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetConfig", + ): ConfigGetReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "GetOper", + ): GetOperReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "MergeConfig", + ): ConfigReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + "ReplaceConfig", + ): ConfigReply.FromString, + } + cardinalities = { + "CliConfig": cardinality.Cardinality.UNARY_UNARY, + "CommitConfig": cardinality.Cardinality.UNARY_UNARY, + "CommitReplace": cardinality.Cardinality.UNARY_UNARY, + "ConfigDiscardChanges": cardinality.Cardinality.UNARY_UNARY, + "CreateSubs": cardinality.Cardinality.UNARY_STREAM, + "DeleteConfig": cardinality.Cardinality.UNARY_UNARY, + "GetConfig": cardinality.Cardinality.UNARY_STREAM, + "GetOper": cardinality.Cardinality.UNARY_STREAM, + "MergeConfig": cardinality.Cardinality.UNARY_UNARY, + "ReplaceConfig": cardinality.Cardinality.UNARY_UNARY, + } + stub_options = beta_implementations.stub_options( + host=host, + metadata_transformer=metadata_transformer, + request_serializers=request_serializers, + response_deserializers=response_deserializers, + thread_pool=pool, + thread_pool_size=pool_size, + ) + return beta_implementations.dynamic_stub( + channel, + "IOSXRExtensibleManagabilityService.gRPCConfigOper", + cardinalities, + options=stub_options, + ) + + +class gRPCExecStub(object): + """ + Should we seperate Exec from Config/Oper? + + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ShowCmdTextOutput = channel.unary_stream( + "/IOSXRExtensibleManagabilityService.gRPCExec/ShowCmdTextOutput", + request_serializer=ShowCmdArgs.SerializeToString, + response_deserializer=ShowCmdTextReply.FromString, + ) + self.ShowCmdJSONOutput = channel.unary_stream( + "/IOSXRExtensibleManagabilityService.gRPCExec/ShowCmdJSONOutput", + request_serializer=ShowCmdArgs.SerializeToString, + response_deserializer=ShowCmdJSONReply.FromString, + ) + + +class gRPCExecServicer(object): + """ + Should we seperate Exec from Config/Oper? + + + """ + + def ShowCmdTextOutput(self, request, context): + """Exec commands""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ShowCmdJSONOutput(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_gRPCExecServicer_to_server(servicer, server): + rpc_method_handlers = { + "ShowCmdTextOutput": grpc.unary_stream_rpc_method_handler( + servicer.ShowCmdTextOutput, + request_deserializer=ShowCmdArgs.FromString, + response_serializer=ShowCmdTextReply.SerializeToString, + ), + "ShowCmdJSONOutput": grpc.unary_stream_rpc_method_handler( + servicer.ShowCmdJSONOutput, + request_deserializer=ShowCmdArgs.FromString, + response_serializer=ShowCmdJSONReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "IOSXRExtensibleManagabilityService.gRPCExec", + rpc_method_handlers, + ) + server.add_generic_rpc_handlers((generic_handler,)) + + +class BetagRPCExecServicer(object): + """ + Should we seperate Exec from Config/Oper? + + + """ + + def ShowCmdTextOutput(self, request, context): + """Exec commands""" + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + def ShowCmdJSONOutput(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + +class BetagRPCExecStub(object): + """ + Should we seperate Exec from Config/Oper? + + + """ + + def ShowCmdTextOutput( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + """Exec commands""" + raise NotImplementedError() + + def ShowCmdJSONOutput( + self, + request, + timeout, + metadata=None, + with_call=False, + protocol_options=None, + ): + raise NotImplementedError() + + +def beta_create_gRPCExec_server( + servicer, + pool=None, + pool_size=None, + default_timeout=None, + maximum_timeout=None, +): + request_deserializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdJSONOutput", + ): ShowCmdArgs.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdTextOutput", + ): ShowCmdArgs.FromString, + } + response_serializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdJSONOutput", + ): ShowCmdJSONReply.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdTextOutput", + ): ShowCmdTextReply.SerializeToString, + } + method_implementations = { + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdJSONOutput", + ): face_utilities.unary_stream_inline(servicer.ShowCmdJSONOutput), + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdTextOutput", + ): face_utilities.unary_stream_inline(servicer.ShowCmdTextOutput), + } + server_options = beta_implementations.server_options( + request_deserializers=request_deserializers, + response_serializers=response_serializers, + thread_pool=pool, + thread_pool_size=pool_size, + default_timeout=default_timeout, + maximum_timeout=maximum_timeout, + ) + return beta_implementations.server( + method_implementations, + options=server_options, + ) + + +def beta_create_gRPCExec_stub( + channel, + host=None, + metadata_transformer=None, + pool=None, + pool_size=None, +): + request_serializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdJSONOutput", + ): ShowCmdArgs.SerializeToString, + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdTextOutput", + ): ShowCmdArgs.SerializeToString, + } + response_deserializers = { + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdJSONOutput", + ): ShowCmdJSONReply.FromString, + ( + "IOSXRExtensibleManagabilityService.gRPCExec", + "ShowCmdTextOutput", + ): ShowCmdTextReply.FromString, + } + cardinalities = { + "ShowCmdJSONOutput": cardinality.Cardinality.UNARY_STREAM, + "ShowCmdTextOutput": cardinality.Cardinality.UNARY_STREAM, + } + stub_options = beta_implementations.stub_options( + host=host, + metadata_transformer=metadata_transformer, + request_serializers=request_serializers, + response_deserializers=response_deserializers, + thread_pool=pool, + thread_pool_size=pool_size, + ) + return beta_implementations.dynamic_stub( + channel, + "IOSXRExtensibleManagabilityService.gRPCExec", + cardinalities, + options=stub_options, + ) + + +# @@protoc_insertion_point(module_scope) diff --git a/ansible_collections/cisco/iosxr/plugins/terminal/__init__.py b/ansible_collections/cisco/iosxr/plugins/terminal/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/terminal/__init__.py diff --git a/ansible_collections/cisco/iosxr/plugins/terminal/iosxr.py b/ansible_collections/cisco/iosxr/plugins/terminal/iosxr.py new file mode 100644 index 00000000..5b60dcd9 --- /dev/null +++ b/ansible_collections/cisco/iosxr/plugins/terminal/iosxr.py @@ -0,0 +1,61 @@ +# +# (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/>. +# +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import re + +from ansible.errors import AnsibleConnectionFailure +from ansible_collections.ansible.netcommon.plugins.plugin_utils.terminal_base import TerminalBase + + +class TerminalModule(TerminalBase): + + terminal_stdout_re = [ + re.compile(rb"[\r\n]*[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(rb"]]>]]>[\r\n]?"), + ] + + terminal_stderr_re = [ + re.compile(rb"% ?Error"), + re.compile(rb"% ?Bad secret"), + re.compile(rb"% ?This command is not authorized"), + re.compile(rb"invalid input", re.I), + re.compile(rb"(?:incomplete|ambiguous) command", re.I), + re.compile(rb"(?<!\()connection timed out(?!\))", re.I), + re.compile(rb"[^\r\n]+ not found", re.I), + re.compile(rb"'[^']' +returned error code: ?\d+"), + re.compile(rb"Failed to commit", re.I), + re.compile(rb"show configuration failed \[inheritance\]", re.I), + ] + + terminal_config_prompt = re.compile(r"^.+\(config(-.*)?\)#$") + + def on_open_shell(self): + try: + for cmd in ( + b"terminal length 0", + b"terminal width 512", + b"terminal exec prompt no-timestamp", + ): + self._exec_cli_command(cmd) + except AnsibleConnectionFailure: + raise AnsibleConnectionFailure("unable to set terminal parameters") |