diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 62bbae52..38c9b455 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -36,9 +36,6 @@ files: $cliconfs/nos.py: maintainers: $team_extreme labels: networking nos - $cliconfs/routeros.py: - maintainers: heuels - labels: networking routeros $cliconfs/slxos.py: maintainers: $team_extreme labels: networking slxos @@ -120,12 +117,6 @@ files: $module_utils/network/ordnance/ordnance.py: maintainers: alexanderturner djh00t labels: networking - $module_utils/network/panos/panos.py: - maintainers: ivanbojer jtschichold shinmog - labels: networking - $module_utils/network/routeros/routeros.py: - maintainers: heuels - labels: networking $module_utils/network/slxos/slxos.py: maintainers: $team_extreme labels: networking @@ -321,41 +312,8 @@ files: $modules/network/ordnance/: authors: alexanderturner maintainers: djh00t - $modules/network/panos/: - authors: ivanbojer jtschichold - maintainers: shinmog - $modules/network/panos/panos_commit.py: - authors: ivanbojer jtschichold traittinen - $modules/network/panos/panos_dag_tags.py: - authors: vinayvenkat - maintainers: ivanbojer jtschichold shinmog - $modules/network/panos/panos_match_rule.py: - authors: rnh556 - maintainers: ivanbojer jtschichold shinmog - $modules/network/panos/panos_nat_rule.py: - authors: ivanbojer jtschichold rnh556 - $modules/network/panos/panos_object.py: - authors: rnh556 - maintainers: ivanbojer jtschichold shinmog - $modules/network/panos/panos_op.py: - authors: ivanbojer - maintainers: jtschichold shinmog - $modules/network/panos/panos_query_rules.py: - authors: rnh556 - maintainers: ivanbojer jtschichold shinmog - $modules/network/panos/panos_sag.py: - authors: vinayvenkat - maintainers: ivanbojer jtschichold shinmog - $modules/network/panos/panos_security_rule.py: - authors: ivanbojer rnh556 - maintainers: jtschichold shinmog - $modules/network/panos/panos_set.py: - authors: spmp - maintainers: ivanbojer jtschichold shinmog $modules/network/radware/: authors: evgenyfedoruk - $modules/network/routeros/: - authors: heuels $modules/network/slxos/: authors: bigmstone maintainers: LindsayHill ujwalkomarla @@ -392,9 +350,6 @@ files: $terminals/nos.py: maintainers: $team_extreme labels: networking nos - $terminals/routeros.py: - maintainers: heuels - labels: networking routeros $terminals/slxos.py: maintainers: $team_extreme labels: networking slxos @@ -421,9 +376,11 @@ macros: modules: plugins/modules terminals: plugins/terminal team_aci: aciguru brunocalogero devarshishah3 fadallar jmcgill298 koladiya mtorelli rsmeyers schunduri smnmtzgr + team_aruba: karthikeyan-dhandapani team_avi: ericsysmin grastogi23 khaltore team_e_spirit: MatrixCrawler getjack team_extreme: LindsayHill bigmstone ujwalkomarla + team_ftd: annikulin team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2 team_lenovo: istaicu mihaibroc team_netscaler: chiradeep giorgos-nikolopoulos diff --git a/changelogs/fragments/101_update_routeros_facts.yml b/changelogs/fragments/101_update_routeros_facts.yml deleted file mode 100644 index d4794df7..00000000 --- a/changelogs/fragments/101_update_routeros_facts.yml +++ /dev/null @@ -1,2 +0,0 @@ -minor_changes: - - routeros_facts - now also collecting data about BGP and OSPF (https://github.com/ansible-collections/community.network/pull/101). diff --git a/changelogs/fragments/104_routeros_facts_export_verbose.yml b/changelogs/fragments/104_routeros_facts_export_verbose.yml deleted file mode 100644 index 2f80ea30..00000000 --- a/changelogs/fragments/104_routeros_facts_export_verbose.yml +++ /dev/null @@ -1,2 +0,0 @@ -minor_changes: - - routeros_facts - set configuration export on to verbose, for full configuration export (https://github.com/ansible-collections/community.network/pull/104). diff --git a/changelogs/fragments/132_remove_nso.yml b/changelogs/fragments/132_remove_nso.yml deleted file mode 100644 index ef035453..00000000 --- a/changelogs/fragments/132_remove_nso.yml +++ /dev/null @@ -1,2 +0,0 @@ -removed_features: -- "nso - remove support for Cisco NSO modules which have been migrated to the cisco.nso namespace" diff --git a/changelogs/fragments/check_point-migration.yml b/changelogs/fragments/check_point-migration.yml new file mode 100644 index 00000000..da9a6355 --- /dev/null +++ b/changelogs/fragments/check_point-migration.yml @@ -0,0 +1,15 @@ +removed_features: +- > + The ``cp_publish`` module has been removed from this collection. + It was a duplicate of ``check_point.mgmt.cp_mgmt_publish`` in the `check_point.mgmt `_ collection. + If you use ansible-base 2.10 or newer, redirections have been provided. + + If you use Ansible 2.9 and installed this collection, you need to adjust the FQCNs (``community.network.cp_publish`` → ``check_point.mgmt.cp_mgmt_publish``) and make sure to install the check_point.mgmt collection. +- The dependency on the ``check_point.mgmt`` collection has been removed. If you depend on that installing ``community.network`` also installs ``check_point.mgmt``, you have to make sure to install ``check_point.mgmt`` explicitly. +breaking_changes: +- > + If you use Ansible 2.9 and the ``cp_publish`` module from this collection, community.network 2.0.0 results in errors when trying to use the module by FQCN, i.e. ``community.network.cp_publish``. + Since Ansible 2.9 is not able to use redirections, you will have to adjust your playbooks and roles manually to use the new FQCNs (``check_point.mgmt.cp_mgmt_publish``) and to make sure that you have ``check_point.mgmt`` installed. + + If you use ansible-base 2.10 or newer and did not install Ansible 3.0.0, but installed (and/or upgraded) community.network manually, you need to make sure to also install ``check_point.mgmt`` if you are using the ``cp_publish`` module. + While ansible-base 2.10 or newer can use the redirects that community.network 2.0.0 adds, the collection they point to (check_point.mgmt) must be installed for them to work. diff --git a/changelogs/fragments/fortimanager-imports.yml b/changelogs/fragments/fortimanager-imports.yml new file mode 100644 index 00000000..0281e005 --- /dev/null +++ b/changelogs/fragments/fortimanager-imports.yml @@ -0,0 +1,4 @@ +bugfixes: +- "fortimanager httpapi plugin - fix imports to load module_utils from fortios.fortimanager, where it actually exists. Please note that you must have the fortios.fortimanager collection installed for the plugin to work (https://github.com/ansible-collections/community.network/pull/151)." +major_changes: +- "In community.network 2.0.0, the ``fortimanager`` httpapi plugin will be removed and replaced by a redirect to the corresponding plugin in the fortios.fortimanager collection. For Ansible 2.10 and ansible-base 2.10 users, this means that it will continue to work assuming that collection is installed. For Ansible 2.9 users, this means that they have to adjust the FQCN from ``community.network.fortimanager`` to ``fortios.fortimanager.fortimanager`` (https://github.com/ansible-collections/community.network/pull/151)." diff --git a/changelogs/fragments/ftd-imports.yml b/changelogs/fragments/ftd-imports.yml new file mode 100644 index 00000000..51e06b43 --- /dev/null +++ b/changelogs/fragments/ftd-imports.yml @@ -0,0 +1,2 @@ +bugfixes: +- "ftd httpapi plugin - make sure that plugin errors out on initialization if the required library is not found, and not on load-time (https://github.com/ansible-collections/community.network/pull/150)." diff --git a/changelogs/fragments/netcommon_ipaddress.yaml b/changelogs/fragments/netcommon_ipaddress.yaml new file mode 100644 index 00000000..61e25103 --- /dev/null +++ b/changelogs/fragments/netcommon_ipaddress.yaml @@ -0,0 +1,7 @@ +--- +breaking_changes: + - cnos_static_route - move ipaddress import from ansible.netcommon to builtin + or package before ipaddress is removed from ansible.netcommon. You need to + make sure to have the ipaddress package installed if you are using this + module on Python 2.7 + (https://github.com/ansible-collections/community.network/pull/129). diff --git a/changelogs/fragments/nso-migration-removal.yml b/changelogs/fragments/nso-migration-removal.yml new file mode 100644 index 00000000..fc1891ec --- /dev/null +++ b/changelogs/fragments/nso-migration-removal.yml @@ -0,0 +1,14 @@ +removed_features: +- | + All ``nso`` modules have been removed from this collection. + They have been migrated to the `cisco.nso `_ collection. + If you use ansible-base 2.10 or newer, redirections have been provided. + + If you use Ansible 2.9 and installed this collection, you need to adjust the FQCNs (``community.network.nso_config`` → ``cisco.nso.nso_config``) and make sure to install the `cisco.nso` collection. +breaking_changes: +- | + If you use Ansible 2.9 and the ``nso`` modules from this collection, community.network 2.0.0 results in errors when trying to use the nso content by FQCN, like ``community.network.nso_config``. + Since Ansible 2.9 is not able to use redirections, you will have to adjust your playbooks and roles manually to use the new FQCNs (``cisco.nso.nso_config`` for the previous example) and to make sure that you have ``cisco.nso`` installed. + + If you use ansible-base 2.10 or newer and did not install Ansible 3.0.0, but installed (and/or upgraded) community.network manually, you need to make sure to also install ``cisco.nso`` if you are using any of the ``nso`` modules. + While ansible-base 2.10 or newer can use the redirects that community.network 2.0.0 adds, the collection they point to (cisco.nso) must be installed for them to work. diff --git a/changelogs/fragments/remove-deprecated-modules.yml b/changelogs/fragments/remove-deprecated-modules.yml new file mode 100644 index 00000000..066477a7 --- /dev/null +++ b/changelogs/fragments/remove-deprecated-modules.yml @@ -0,0 +1,3 @@ +removed_features: +- The deprecated Pluribus Networks modules ``pn_cluster``, ``pn_ospf``, ``pn_ospfarea``, ``pn_show``, ``pn_trunk``, ``pn_vlag``, ``pn_vlan``, ``pn_vrouter``, ``pn_vrouterbgp``, ``pn_vrouterif``, ``pn_vrouterlbif`` have been removed (https://github.com/ansible-collections/community.network/pull/176). +- The deprecated modules ``panos_admin``, ``panos_admpwd``, ``panos_cert_gen_ssh``, ``panos_check``, ``panos_commit``, ``panos_dag``, ``panos_dag_tags``, ``panos_import``, ``panos_interface``, ``panos_lic``, ``panos_loadcfg``, ``panos_match_rule``, ``panos_mgtconfig``, ``panos_nat_rule``, ``panos_object``, ``panos_op``, ``panos_pg``, ``panos_query_rules``, ``panos_restart``, ``panos_sag``, ``panos_security_rule``, ``panos_set`` have been removed. Use modules from the `paloaltonetworks.panos collection `_ instead (https://github.com/ansible-collections/community.network/pull/176). diff --git a/changelogs/fragments/remove-deprecated-redirects.yml b/changelogs/fragments/remove-deprecated-redirects.yml new file mode 100644 index 00000000..aa8044c1 --- /dev/null +++ b/changelogs/fragments/remove-deprecated-redirects.yml @@ -0,0 +1,2 @@ +removed_features: +- "The redirect to the ``mellanox.onyx`` collection was removed for: the ``onyx`` cliconf plugin, terminal plugin, module_utils, action plugin, doc fragment, and the following modules: ``onyx_aaa``, ``onyx_bfd``, ``onyx_bgp``, ``onyx_buffer_pool``, ``onyx_command``, ``onyx_config``, ``onyx_facts``, ``onyx_igmp``, ``onyx_igmp_interface``, ``onyx_igmp_vlan``, ``onyx_interface``, ``onyx_l2_interface``, ``onyx_l3_interface``, ``onyx_linkagg``, ``onyx_lldp``, ``onyx_lldp_interface``, ``onyx_magp``, ``onyx_mlag_ipl``, ``onyx_mlag_vip``, ``onyx_ntp``, ``onyx_ntp_servers_peers``, ``onyx_ospf``, ``onyx_pfc_interface``, ``onyx_protocol``, ``onyx_ptp_global``, ``onyx_ptp_interface``, ``onyx_qos``, ``onyx_snmp``, ``onyx_snmp_hosts``, ``onyx_snmp_users``, ``onyx_syslog_files``, ``onyx_syslog_remote``, ``onyx_traffic_class``, ``onyx_username``, ``onyx_vlan``, ``onyx_vxlan``, ``onyx_wjh`` (https://github.com/ansible-collections/community.network/pull/175)." diff --git a/changelogs/fragments/routeros-3-api-ssl.yml b/changelogs/fragments/routeros-3-api-ssl.yml deleted file mode 100644 index 245d16d6..00000000 --- a/changelogs/fragments/routeros-3-api-ssl.yml +++ /dev/null @@ -1,2 +0,0 @@ -bugfixes: -- "api - fix crash when the ``ssl`` parameter is used (https://github.com/ansible-collections/community.routeros/pull/3)." diff --git a/changelogs/fragments/routeros-migration-removal.yml b/changelogs/fragments/routeros-migration-removal.yml new file mode 100644 index 00000000..39d5081d --- /dev/null +++ b/changelogs/fragments/routeros-migration-removal.yml @@ -0,0 +1,14 @@ +removed_features: +- | + All ``routeros`` modules and plugins have been removed from this collection. + They have been migrated to the `community.routeros `_ collection. + If you use ansible-base 2.10 or newer, redirections have been provided. + + If you use Ansible 2.9 and installed this collection, you need to adjust the FQCNs (``community.network.routeros_command`` → ``community.routeros.command``) and make sure to install the community.routeros collection. +breaking_changes: +- | + If you use Ansible 2.9 and the ``routeros`` plugins or modules from this collections, community.network 2.0.0 results in errors when trying to use the routeros content by FQCN, like ``community.network.routeros_command``. + Since Ansible 2.9 is not able to use redirections, you will have to adjust your playbooks and roles manually to use the new FQCNs (``community.routeros.command`` for the previous example) and to make sure that you have ``community.routeros`` installed. + + If you use ansible-base 2.10 or newer and did not install Ansible 3.0.0, but installed (and/or upgraded) community.network manually, you need to make sure to also install ``community.routeros`` if you are using any of the ``routeros`` plugins or modules. + While ansible-base 2.10 or newer can use the redirects that community.network 2.0.0 adds, the collection they point to (community.routeros) must be installed for them to work. diff --git a/galaxy.yml b/galaxy.yml index aee5e95e..36c5a0a8 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: community name: network -version: 1.3.0 +version: 2.0.0 readme: README.md authors: - Ansible (https://github.com/ansible) @@ -10,7 +10,6 @@ tags: [community, network] # NOTE: No more dependencies can be added to this list dependencies: ansible.netcommon: '>=1.0.0' - check_point.mgmt: '>=1.0.0' fortinet.fortios: '>=1.0.0' repository: https://github.com/ansible-collections/community.network documentation: https://docs.ansible.com/ansible/latest/collections/community/network/ diff --git a/meta/runtime.yml b/meta/runtime.yml index 7addef02..1316c3f0 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,395 +1,170 @@ +--- requires_ansible: '>=2.9.10' plugin_routing: modules: + nso_config: + redirect: cisco.nso.nso_config + nso_action: + redirect: cisco.nso.nso_action + nso_verify: + redirect: cisco.nso.nso_verify + nso_query: + redirect: cisco.nso.nso_query + nso_show: + redirect: cisco.nso.nso_show + cp_publish: + redirect: check_point.mgmt.cp_mgmt_publish pn_cluster: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_ospf: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_ospfarea: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_show: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_trunk: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vlag: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vlan: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vrouter: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vrouterbgp: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vrouterif: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. pn_vrouterlbif: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: The module has been removed without a documented replacement. panos_admin: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_admpwd: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_cert_gen_ssh: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_check: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_commit: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_dag: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_dag_tags: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_import: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_interface: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_lic: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_loadcfg: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_match_rule: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_mgtconfig: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_nat_rule: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_object: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_op: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_pg: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_query_rules: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_restart: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_sag: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_security_rule: - deprecation: + tombstone: removal_version: 2.0.0 - warning_text: see plugin documentation for details + warning_text: Use modules from the paloaltonetworks.panos collection instead. panos_set: - deprecation: - removal_version: 2.0.0 - warning_text: see plugin documentation for details - nso_config: - deprecation: - removal_version: 2.0.0 - warning_text: The nso_config module has been moved to the cisco.nso collection - redirect: cisco.nso - nso_action: - deprecation: - removal_version: 2.0.0 - warning_text: The nso_action module has been moved to the cisco.nso collection - redirect: cisco.nso - nso_query: - deprecation: - removal_version: 2.0.0 - warning_text: The nso_query module has been moved to the cisco.nso collection - redirect: cisco.nso - nso_verify: - deprecation: - removal_version: 2.0.0 - warning_text: The nso_verify module has been moved to the cisco.nso collection - redirect: cisco.nso - nso_show: - deprecation: - removal_version: 2.0.0 - warning_text: The nso_show module has been moved to the cisco.nso collection - redirect: cisco.nso - onyx_aaa: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_aaa module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_aaa - onyx_bfd: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_bfd module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_bfd - onyx_bgp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_bgp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_bgp - onyx_buffer_pool: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_buffer_pool module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_buffer_pool - onyx_command: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_command module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_command - onyx_config: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_config module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_config - onyx_facts: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_facts module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_facts - onyx_igmp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_igmp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_igmp - onyx_igmp_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_igmp_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_igmp_interface - onyx_igmp_vlan: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_igmp_vlan module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_igmp_vlan - onyx_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_interface - onyx_l2_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_l2_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_l2_interface - onyx_l3_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_l3_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_l3_interface - onyx_linkagg: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_linkagg module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_linkagg - onyx_lldp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_lldp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_lldp - onyx_lldp_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_lldp_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_lldp_interface - onyx_magp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_magp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_magp - onyx_mlag_ipl: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_mlag_ipl module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_mlag_ipl - onyx_mlag_vip: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_mlag_vip module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_mlag_vip - onyx_ntp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_ntp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_ntp - onyx_ntp_servers_peers: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_ntp_servers_peers module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_ntp_servers_peers - onyx_ospf: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_ospf module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_ospf - onyx_pfc_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_pfc_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_pfc_interface - onyx_protocol: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_protocol module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_protocol - onyx_ptp_global: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_ptp_global module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_ptp_global - onyx_ptp_interface: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_ptp_interface module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_ptp_interface - onyx_qos: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_qos module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_qos - onyx_snmp: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_snmp module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_snmp - onyx_snmp_hosts: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_snmp_hosts module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_snmp_hosts - onyx_snmp_users: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_snmp_users module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_snmp_users - onyx_syslog_files: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_syslog_files module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_syslog_files - onyx_syslog_remote: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_syslog_remote module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_syslog_remote - onyx_traffic_class: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_traffic_class module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_traffic_class - onyx_username: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_username module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_username - onyx_vlan: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_vlan module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_vlan - onyx_vxlan: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_vxlan module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_vxlan - onyx_wjh: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_wjh module has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_wjh - cliconf: - onyx: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx cliconf plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx - terminal: - onyx: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx terminal plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx + tombstone: + removal_version: 2.0.0 + warning_text: Use modules from the paloaltonetworks.panos collection instead. + routeros_api: + redirect: community.routeros.api + routeros_command: + redirect: community.routeros.command + routeros_facts: + redirect: community.routeros.facts module_utils: - network.nso: - deprecation: - removal_version: 2.0.0 - warning_text: The nso module_utils plugin has been moved to the cisco.nso collection - redirect: cisco.nso - network.onyx: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx module_utils plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.network.onyx - network.onyx.onyx: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx module_utils plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.network.onyx.onyx - action: - onyx_config: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx_config action plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx_config - doc_fragments: - nso: - deprecation: - removal_version: 2.0.0 - warning_text: The nso doc_fragments plugin has been moved to the cisco.nso collection + network.routeros.routeros: + redirect: community.routeros.routeros + network.nso.nso: redirect: cisco.nso.nso - onyx: - deprecation: - removal_version: 2.0.0 - warning_text: The onyx doc_fragments plugin has been moved to the mellanox.onyx collection - redirect: mellanox.onyx.onyx + cliconf: + routeros: + redirect: community.routeros.routeros netconf: sros: deprecation: removal_version: 3.0.0 warning_text: see plugin documentation for details + terminal: + routeros: + redirect: community.routeros.routeros diff --git a/plugins/action/aireos.py b/plugins/action/aireos.py index 45bdfb43..c947afb9 100644 --- a/plugins/action/aireos.py +++ b/plugins/action/aireos.py @@ -25,7 +25,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.aireos.aireos import aireos_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/action/aruba.py b/plugins/action/aruba.py index 01591747..716cf6c5 100644 --- a/plugins/action/aruba.py +++ b/plugins/action/aruba.py @@ -25,7 +25,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.aruba.aruba import aruba_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/action/ce.py b/plugins/action/ce.py index 57e8c1f5..0b5498f0 100644 --- a/plugins/action/ce.py +++ b/plugins/action/ce.py @@ -12,7 +12,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import ce_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/action/cnos.py b/plugins/action/cnos.py index c2444303..49473d0c 100644 --- a/plugins/action/cnos.py +++ b/plugins/action/cnos.py @@ -23,7 +23,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.cnos.cnos import cnos_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/action/enos.py b/plugins/action/enos.py index df8cc26e..019f2872 100644 --- a/plugins/action/enos.py +++ b/plugins/action/enos.py @@ -23,7 +23,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.enos.enos import enos_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/action/ironware.py b/plugins/action/ironware.py index ad334f5b..337fd888 100644 --- a/plugins/action/ironware.py +++ b/plugins/action/ironware.py @@ -23,7 +23,6 @@ import copy from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible_collections.community.network.plugins.module_utils.network.ironware.ironware import ironware_provider_spec from ansible.utils.display import Display diff --git a/plugins/action/sros.py b/plugins/action/sros.py index d8a52f67..05485df2 100644 --- a/plugins/action/sros.py +++ b/plugins/action/sros.py @@ -25,7 +25,6 @@ from ansible import constants as C from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.community.network.plugins.module_utils.network.sros.sros import sros_provider_spec -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.warnings import deprecate from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider from ansible.utils.display import Display diff --git a/plugins/cliconf/routeros.py b/plugins/cliconf/routeros.py deleted file mode 100644 index 11b54534..00000000 --- a/plugins/cliconf/routeros.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# (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 . -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -author: Unknown (!UNKNOWN) -cliconf: routeros -short_description: Use routeros cliconf to run command on MikroTik RouterOS platform -description: - - This routeros plugin provides low level abstraction apis for - sending and receiving CLI commands from MikroTik RouterOS network devices. -''' - -import re -import json - -from itertools import chain - -from ansible.module_utils._text import to_bytes, to_text -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list -from ansible.plugins.cliconf import CliconfBase, enable_mode - - -class Cliconf(CliconfBase): - - def get_device_info(self): - device_info = {} - device_info['network_os'] = 'RouterOS' - - resource = self.get('/system resource print') - data = to_text(resource, errors='surrogate_or_strict').strip() - match = re.search(r'version: (\S+)', data) - if match: - device_info['network_os_version'] = match.group(1) - - routerboard = self.get('/system routerboard print') - data = to_text(routerboard, errors='surrogate_or_strict').strip() - match = re.search(r'model: (.+)$', data, re.M) - if match: - device_info['network_os_model'] = match.group(1) - - identity = self.get('/system identity print') - data = to_text(identity, errors='surrogate_or_strict').strip() - match = re.search(r'name: (.+)$', data, re.M) - if match: - device_info['network_os_hostname'] = match.group(1) - - return device_info - - def get_config(self, source='running', format='text', flags=None): - return - - def edit_config(self, command): - return - - def get(self, command, prompt=None, answer=None, sendonly=False, newline=True, check_all=False): - return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all) - - def get_capabilities(self): - result = super(Cliconf, self).get_capabilities() - return json.dumps(result) diff --git a/plugins/doc_fragments/avi.py b/plugins/doc_fragments/avi.py index 8aae649e..e4b5f898 100644 --- a/plugins/doc_fragments/avi.py +++ b/plugins/doc_fragments/avi.py @@ -93,6 +93,7 @@ class ModuleDocFragment(object): description: - It disables avi session information to be cached as a fact. type: bool + default: false notes: - For more information on using Ansible to manage Avi Network devices see U(https://www.ansible.com/ansible-avi-networks). diff --git a/plugins/doc_fragments/panos.py b/plugins/doc_fragments/panos.py deleted file mode 100644 index 870b99b5..00000000 --- a/plugins/doc_fragments/panos.py +++ /dev/null @@ -1,246 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2016, techbizdev -# Copyright: (c) 2018, Kevin Breit (@kbreit) -# 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 - - -class ModuleDocFragment(object): - # Standard files documentation fragment - DOCUMENTATION = r''' -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device. - type: str - required: true - password: - description: - - Password for authentication. - type: str - required: true - username: - description: - - Username for authentication. - type: str - default: admin -''' - - PROVIDER = r''' -options: - provider: - description: - - A dict object containing connection details. - required: true - suboptions: - ip_address: - description: - - The IP address or hostname of the PAN-OS device being configured. - type: str - required: true - username: - description: - - The username to use for authentication. This is ignored if - I(api_key) is specified. - type: str - default: 'admin' - password: - description: - - The password to use for authentication. This is ignored if - I(api_key) is specified. - type: str - api_key: - description: - - The API key to use instead of generating it using - I(username) / I(password). - type: str - port: - description: - - The port number to connect to the PAN-OS device on. - type: int - default: 443 - serial_number: - description: - - The serial number of a firewall to use for targeted commands. - If I(ip_address) is not a Panorama PAN-OS device, then - this param is ignored. - type: str -''' - - TRANSITIONAL_PROVIDER = r''' -options: - provider: - description: - - A dict object containing connection details. - suboptions: - ip_address: - description: - - The IP address or hostname of the PAN-OS device being configured. - type: str - username: - description: - - The username to use for authentication. This is ignored if - I(api_key) is specified. - type: str - default: 'admin' - password: - description: - - The password to use for authentication. This is ignored if - I(api_key) is specified. - type: str - api_key: - description: - - The API key to use instead of generating it using - I(username) / I(password). - type: str - port: - description: - - The port number to connect to the PAN-OS device on. - type: int - default: 443 - serial_number: - description: - - The serial number of a firewall to use for targeted commands. - If I(ip_address) is not a Panorama PAN-OS device, then - this param is ignored. - type: str - ip_address: - description: - - B(Deprecated) - - Use I(provider) to specify PAN-OS connectivity instead. - - HORIZONTALLINE - - The IP address or hostname of the PAN-OS device being configured. - type: str - username: - description: - - B(Deprecated) - - Use I(provider) to specify PAN-OS connectivity instead. - - HORIZONTALLINE - - The username to use for authentication. This is ignored if - I(api_key) is specified. - type: str - default: 'admin' - password: - description: - - B(Deprecated) - - Use I(provider) to specify PAN-OS connectivity instead. - - HORIZONTALLINE - - The password to use for authentication. This is ignored if - I(api_key) is specified. - type: str - api_key: - description: - - B(Deprecated) - - Use I(provider) to specify PAN-OS connectivity instead. - - HORIZONTALLINE - - The API key to use instead of generating it using - I(username) / I(password). - type: str - port: - description: - - B(Deprecated) - - Use I(provider) to specify PAN-OS connectivity instead. - - HORIZONTALLINE - - The port number to connect to the PAN-OS device on. - type: int - default: 443 -notes: - - PAN-OS connectivity should be specified using I(provider) or the - classic PAN-OS connectivity params (I(ip_address), I(username), - I(password), I(api_key), and I(port)). If both are present, then the - classic params are ignored. -''' - - STATE = r''' -options: - state: - description: - - The state. - type: str - default: present - choices: - - present - - absent -''' - - RULEBASE = r''' -options: - rulebase: - description: - - The rulebase in which the rule is to exist. If left unspecified, - this defaults to I(rulebase=pre-rulebase) for Panorama. For - NGFW, this is always set to be I(rulebase=rulebase). - type: str - choices: - - pre-rulebase - - rulebase - - post-rulebase -''' - - VSYS_DG = r''' -options: - vsys_dg: - description: - - The vsys (for NGFW) or device group (for Panorama) this - operation should target. If left unspecified, this defaults to - I(vsys_dg=vsys1) for NGFW or I(vsys_dg=shared) for Panorama. - type: str -''' - - DEVICE_GROUP = r''' -options: - device_group: - description: - - (Panorama only) The device group the operation should target. - type: str - default: shared -''' - - VSYS_IMPORT = r''' -options: - vsys: - description: - - The vsys this object should be imported into. Objects that are - imported include interfaces, virtual routers, virtual wires, and - VLANs. Interfaces are typically imported into vsys1 if no vsys - is specified. - type: str -''' - - VSYS = r''' -options: - vsys: - description: - - The vsys this object belongs to. - type: str - default: vsys1 -''' - - TEMPLATE_ONLY = r''' -options: - template: - description: - - (Panorama only) The template this operation should target. This - param is required if the PAN-OS device is Panorama. - type: str -''' - - FULL_TEMPLATE_SUPPORT = r''' -options: - template: - description: - - (Panorama only) The template this operation should target. - Mutually exclusive with I(template_stack). - type: str - template_stack: - description: - - (Panorama only) The template stack this operation should target. - Mutually exclusive with I(template). - type: str -notes: - - If the PAN-OS to be configured is Panorama, either I(template) or - I(template_stack) must be specified. -''' diff --git a/plugins/httpapi/fortimanager.py b/plugins/httpapi/fortimanager.py index 1c80c280..6ca9a42e 100644 --- a/plugins/httpapi/fortimanager.py +++ b/plugins/httpapi/fortimanager.py @@ -33,12 +33,18 @@ ''' import json +from ansible.errors import AnsibleError from ansible.plugins.httpapi import HttpApiBase from ansible.module_utils.basic import to_text -from ansible_collections.fortinet.fortios.plugins.module_utils.network.fortimanager.common import BASE_HEADERS -from ansible_collections.fortinet.fortios.plugins.module_utils.network.fortimanager.common import FMGBaseException -from ansible_collections.fortinet.fortios.plugins.module_utils.network.fortimanager.common import FMGRCommon -from ansible_collections.fortinet.fortios.plugins.module_utils.network.fortimanager.common import FMGRMethods + +try: + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import BASE_HEADERS + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGBaseException + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRCommon + from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRMethods + HAS_FORTIMANAGER_COLLECTION = True +except ImportError: + HAS_FORTIMANAGER_COLLECTION = False class HttpApi(HttpApiBase): @@ -62,6 +68,8 @@ def __init__(self, connection): self._uses_adoms = False self._adom_list = list() self._logged_in_user = None + if not HAS_FORTIMANAGER_COLLECTION: + raise AnsibleError("The community.network.fortimanager httpapi plugin requires the fortios.fortimanager collection.") def set_become(self, become_context): """ diff --git a/plugins/httpapi/ftd.py b/plugins/httpapi/ftd.py index cc01a879..5400438e 100644 --- a/plugins/httpapi/ftd.py +++ b/plugins/httpapi/ftd.py @@ -51,16 +51,22 @@ from ansible import __version__ as ansible_version from ansible.module_utils.basic import to_text -from ansible.errors import AnsibleConnectionFailure +from ansible.errors import AnsibleConnectionFailure, AnsibleError from ansible_collections.community.network.plugins.module_utils.network.ftd.fdm_swagger_client import FdmSwaggerParser, SpecProp, FdmSwaggerValidator from ansible_collections.community.network.plugins.module_utils.network.ftd.common import HTTPMethod, ResponseParams from ansible.module_utils.six.moves.urllib.error import HTTPError from ansible.module_utils.six.moves.urllib.parse import urlencode from ansible.plugins.httpapi import HttpApiBase -from urllib3 import encode_multipart_formdata -from urllib3.fields import RequestField from ansible.module_utils.connection import ConnectionError +try: + from urllib3 import encode_multipart_formdata + from urllib3.fields import RequestField + HAS_URLLIB3 = True +except ImportError: + HAS_URLLIB3 = False + + BASE_HEADERS = { 'Content-Type': 'application/json', 'Accept': 'application/json', @@ -89,6 +95,9 @@ def __init__(self, connection): self._api_spec = None self._api_validator = None self._ignore_http_errors = False + if not HAS_URLLIB3: + raise AnsibleError( + 'The community.network.ftd httpapi plugin requires urllib3. Use `pip install urllib3` to install it') def login(self, username, password): def request_token_payload(username, password): diff --git a/plugins/module_utils/network/checkpoint/__init__.py b/plugins/module_utils/network/checkpoint/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/plugins/module_utils/network/panos/__init__.py b/plugins/module_utils/network/panos/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/plugins/module_utils/network/panos/panos.py b/plugins/module_utils/network/panos/panos.py deleted file mode 100644 index 1cc9ec72..00000000 --- a/plugins/module_utils/network/panos/panos.py +++ /dev/null @@ -1,418 +0,0 @@ -# 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) 2018 Palo Alto Networks techbizdev, -# -# 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 - - -_MIN_VERSION_ERROR = '{0} version ({1}) < minimum version ({2})' -HAS_PANDEVICE = True -try: - import pandevice - from pandevice.base import PanDevice - from pandevice.firewall import Firewall - from pandevice.panorama import DeviceGroup, Template, TemplateStack - from pandevice.policies import PreRulebase, PostRulebase, Rulebase - from pandevice.device import Vsys - from pandevice.errors import PanDeviceError -except ImportError: - HAS_PANDEVICE = False - - -def _vstr(val): - return '{0}.{1}.{2}'.format(*val) - - -class ConnectionHelper(object): - def __init__(self, min_pandevice_version, min_panos_version, - panorama_error, firewall_error): - """Performs connection initialization and determines params.""" - # Params for AnsibleModule. - self.argument_spec = {} - self.required_one_of = [] - - # Params for pandevice tree construction. - self.vsys = None - self.device_group = None - self.vsys_dg = None - self.rulebase = None - self.template = None - self.template_stack = None - self.vsys_importable = None - self.min_pandevice_version = min_pandevice_version - self.min_panos_version = min_panos_version - self.panorama_error = panorama_error - self.firewall_error = firewall_error - - # The PAN-OS device. - self.device = None - - def get_pandevice_parent(self, module): - """Builds the pandevice object tree, returning the parent object. - - If pandevice is not installed, then module.fail_json() will be - invoked. - - Arguments: - * module(AnsibleModule): the ansible module. - - Returns: - * The parent pandevice object based on the spec given to - get_connection(). - """ - # Sanity check. - if not HAS_PANDEVICE: - module.fail_json(msg='Missing required library "pandevice".') - - # Verify pandevice minimum version. - if self.min_pandevice_version is not None: - pdv = tuple(int(x) for x in pandevice.__version__.split('.')) - if pdv < self.min_pandevice_version: - module.fail_json(msg=_MIN_VERSION_ERROR.format( - 'pandevice', pandevice.__version__, - _vstr(self.min_pandevice_version))) - - pan_device_auth, serial_number = None, None - if module.params['provider'] and module.params['provider']['ip_address']: - pan_device_auth = ( - module.params['provider']['ip_address'], - module.params['provider']['username'], - module.params['provider']['password'], - module.params['provider']['api_key'], - module.params['provider']['port'], - ) - serial_number = module.params['provider']['serial_number'] - elif module.params.get('ip_address', None) is not None: - pan_device_auth = ( - module.params['ip_address'], - module.params['username'], - module.params['password'], - module.params['api_key'], - module.params['port'], - ) - msg = 'Classic provider params are deprecated; use "provider" instead' - module.deprecate(msg, version='2.0.0', collection_name='community.network') # was Ansible 2.12 - else: - module.fail_json(msg='Provider params are required.') - - # Create the connection object. - try: - self.device = PanDevice.create_from_device(*pan_device_auth) - except PanDeviceError as e: - module.fail_json(msg='Failed connection: {0}'.format(e)) - - # Verify PAN-OS minimum version. - if self.min_panos_version is not None: - if self.device._version_info < self.min_panos_version: - module.fail_json(msg=_MIN_VERSION_ERROR.format( - 'PAN-OS', _vstr(self.device._version_info), - _vstr(self.min_panos_version))) - - # Optional: Firewall via Panorama connectivity specified. - if hasattr(self.device, 'refresh_devices') and serial_number: - fw = Firewall(serial=serial_number) - self.device.add(fw) - self.device = fw - - parent = self.device - not_found = '{0} "{1}" is not present.' - pano_mia_param = 'Param "{0}" is required for Panorama but not specified.' - ts_error = 'Specify either the template or the template stack{0}.' - if hasattr(self.device, 'refresh_devices'): - # Panorama connection. - # Error if Panorama is not supported. - if self.panorama_error is not None: - module.fail_json(msg=self.panorama_error) - - # Spec: template stack. - tmpl_required = False - added_template = False - if self.template_stack is not None: - name = module.params[self.template_stack] - if name is not None: - stacks = TemplateStack.refreshall(parent, name_only=True) - for ts in stacks: - if ts.name == name: - parent = ts - added_template = True - break - else: - module.fail_json(msg=not_found.format( - 'Template stack', name, - )) - elif self.template is not None: - tmpl_required = True - else: - module.fail_json(msg=pano_mia_param.format(self.template_stack)) - - # Spec: template. - if self.template is not None: - name = module.params[self.template] - if name is not None: - if added_template: - module.fail_json(msg=ts_error.format(', not both')) - templates = Template.refreshall(parent, name_only=True) - for t in templates: - if t.name == name: - parent = t - break - else: - module.fail_json(msg=not_found.format( - 'Template', name, - )) - elif tmpl_required: - module.fail_json(msg=ts_error.format('')) - else: - module.fail_json(msg=pano_mia_param.format(self.template)) - - # Spec: vsys importable. - vsys_name = self.vsys_importable or self.vsys - if vsys_name is not None: - name = module.params[vsys_name] - if name not in (None, 'shared'): - vo = Vsys(name) - parent.add(vo) - parent = vo - - # Spec: vsys_dg or device_group. - dg_name = self.vsys_dg or self.device_group - if dg_name is not None: - name = module.params[dg_name] - if name not in (None, 'shared'): - groups = DeviceGroup.refreshall(parent, name_only=True) - for dg in groups: - if dg.name == name: - parent = dg - break - else: - module.fail_json(msg=not_found.format( - 'Device group', name, - )) - - # Spec: rulebase. - if self.rulebase is not None: - if module.params[self.rulebase] in (None, 'pre-rulebase'): - rb = PreRulebase() - parent.add(rb) - parent = rb - elif module.params[self.rulebase] == 'rulebase': - rb = Rulebase() - parent.add(rb) - parent = rb - elif module.params[self.rulebase] == 'post-rulebase': - rb = PostRulebase() - parent.add(rb) - parent = rb - else: - module.fail_json(msg=not_found.format( - 'Rulebase', module.params[self.rulebase])) - else: - # Firewall connection. - # Error if firewalls are not supported. - if self.firewall_error is not None: - module.fail_json(msg=self.firewall_error) - - # Spec: vsys or vsys_dg or vsys_importable. - vsys_name = self.vsys_dg or self.vsys or self.vsys_importable - if vsys_name is not None: - parent.vsys = module.params[vsys_name] - - # Spec: rulebase. - if self.rulebase is not None: - rb = Rulebase() - parent.add(rb) - parent = rb - - # Done. - return parent - - -def get_connection(vsys=None, device_group=None, - vsys_dg=None, vsys_importable=None, - rulebase=None, template=None, template_stack=None, - with_classic_provider_spec=False, with_state=True, - argument_spec=None, required_one_of=None, - min_pandevice_version=None, min_panos_version=None, - panorama_error=None, firewall_error=None): - """Returns a helper object that handles pandevice object tree init. - - The `vsys`, `device_group`, `vsys_dg`, `vsys_importable`, `rulebase`, - `template`, and `template_stack` params can be any of the following types: - - * None - do not include this in the spec - * True - use the default param name - * string - use this string for the param name - - The `min_pandevice_version` and `min_panos_version` args expect a 3 element - tuple of ints. For example, `(0, 6, 0)` or `(8, 1, 0)`. - - If you are including template support (by defining either `template` and/or - `template_stack`), and the thing the module is enabling the management of is - an "importable", you should define either `vsys_importable` (whose default - value is None) or `vsys` (whose default value is 'vsys1'). - - Arguments: - vsys: The vsys (default: 'vsys1'). - device_group: Panorama only - The device group (default: 'shared'). - vsys_dg: The param name if vsys and device_group are a shared param. - vsys_importable: Either this or `vsys` should be specified. For: - - Interfaces - - VLANs - - Virtual Wires - - Virtual Routers - rulebase: This is a policy of some sort. - template: Panorama - The template name. - template_stack: Panorama - The template stack name. - with_classic_provider_spec(bool): Include the ip_address, username, - password, api_key, and port params in the base spec, and make the - "provider" param optional. - with_state(bool): Include the standard 'state' param. - argument_spec(dict): The argument spec to mixin with the - generated spec based on the given parameters. - required_one_of(list): List of lists to extend into required_one_of. - min_pandevice_version(tuple): Minimum pandevice version allowed. - min_panos_version(tuple): Minimum PAN-OS version allowed. - panorama_error(str): The error message if the device is Panorama. - firewall_error(str): The error message if the device is a firewall. - - Returns: - ConnectionHelper - """ - helper = ConnectionHelper( - min_pandevice_version, min_panos_version, - panorama_error, firewall_error) - req = [] - spec = { - 'provider': { - 'required': True, - 'type': 'dict', - 'required_one_of': [['password', 'api_key'], ], - 'options': { - 'ip_address': {'required': True}, - 'username': {'default': 'admin'}, - 'password': {'no_log': True}, - 'api_key': {'no_log': True}, - 'port': {'default': 443, 'type': 'int'}, - 'serial_number': {'no_log': True}, - }, - }, - } - - if with_classic_provider_spec: - spec['provider']['required'] = False - spec['provider']['options']['ip_address']['required'] = False - del(spec['provider']['required_one_of']) - spec.update({ - 'ip_address': {'required': False}, - 'username': {'default': 'admin'}, - 'password': {'no_log': True}, - 'api_key': {'no_log': True}, - 'port': {'default': 443, 'type': 'int'}, - }) - req.extend([ - ['provider', 'ip_address'], - ['provider', 'password', 'api_key'], - ]) - - if with_state: - spec['state'] = { - 'default': 'present', - 'choices': ['present', 'absent'], - } - - if vsys_dg is not None: - if isinstance(vsys_dg, bool): - param = 'vsys_dg' - else: - param = vsys_dg - spec[param] = {} - helper.vsys_dg = param - else: - if vsys is not None: - if isinstance(vsys, bool): - param = 'vsys' - else: - param = vsys - spec[param] = {'default': 'vsys1'} - helper.vsys = param - if device_group is not None: - if isinstance(device_group, bool): - param = 'device_group' - else: - param = device_group - spec[param] = {'default': 'shared'} - helper.device_group = param - if vsys_importable is not None: - if vsys is not None: - raise KeyError('Define "vsys" or "vsys_importable", not both.') - if isinstance(vsys_importable, bool): - param = 'vsys' - else: - param = vsys_importable - spec[param] = {} - helper.vsys_importable = param - - if rulebase is not None: - if isinstance(rulebase, bool): - param = 'rulebase' - else: - param = rulebase - spec[param] = { - 'default': None, - 'choices': ['pre-rulebase', 'rulebase', 'post-rulebase'], - } - helper.rulebase = param - - if template is not None: - if isinstance(template, bool): - param = 'template' - else: - param = template - spec[param] = {} - helper.template = param - - if template_stack is not None: - if isinstance(template_stack, bool): - param = 'template_stack' - else: - param = template_stack - spec[param] = {} - helper.template_stack = param - - if argument_spec is not None: - for k in argument_spec.keys(): - if k in spec: - raise KeyError('{0}: key used by connection helper.'.format(k)) - spec[k] = argument_spec[k] - - if required_one_of is not None: - req.extend(required_one_of) - - # Done. - helper.argument_spec = spec - helper.required_one_of = req - return helper diff --git a/plugins/module_utils/network/routeros/__init__.py b/plugins/module_utils/network/routeros/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/plugins/module_utils/network/routeros/routeros.py b/plugins/module_utils/network/routeros/routeros.py deleted file mode 100644 index 0d9a7c18..00000000 --- a/plugins/module_utils/network/routeros/routeros.py +++ /dev/null @@ -1,163 +0,0 @@ -# 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. -# -# (c) 2016 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 -from ansible.module_utils._text import to_text, to_native -from ansible.module_utils.basic import env_fallback -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list, ComplexList -from ansible.module_utils.connection import Connection, ConnectionError - -_DEVICE_CONFIGS = {} - -routeros_provider_spec = { - 'host': dict(), - 'port': dict(type='int'), - 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), - 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - 'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'), - 'timeout': dict(type='int') -} -routeros_argument_spec = {} - - -def get_provider_argspec(): - return routeros_provider_spec - - -def get_connection(module): - if hasattr(module, '_routeros_connection'): - return module._routeros_connection - - capabilities = get_capabilities(module) - network_api = capabilities.get('network_api') - if network_api == 'cliconf': - module._routeros_connection = Connection(module._socket_path) - else: - module.fail_json(msg='Invalid connection type %s' % network_api) - - return module._routeros_connection - - -def get_capabilities(module): - if hasattr(module, '_routeros_capabilities'): - return module._routeros_capabilities - - try: - capabilities = Connection(module._socket_path).get_capabilities() - module._routeros_capabilities = json.loads(capabilities) - return module._routeros_capabilities - except ConnectionError as exc: - module.fail_json(msg=to_native(exc, errors='surrogate_then_replace')) - - -def get_defaults_flag(module): - connection = get_connection(module) - - try: - out = connection.get('/system default-configuration print') - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - out = to_text(out, errors='surrogate_then_replace') - - commands = set() - for line in out.splitlines(): - if line.strip(): - commands.add(line.strip().split()[0]) - - if 'all' in commands: - return ['all'] - else: - return ['full'] - - -def get_config(module, flags=None): - flag_str = ' '.join(to_list(flags)) - - try: - return _DEVICE_CONFIGS[flag_str] - except KeyError: - connection = get_connection(module) - - try: - out = connection.get_config(flags=flags) - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - cfg = to_text(out, errors='surrogate_then_replace').strip() - _DEVICE_CONFIGS[flag_str] = cfg - return cfg - - -def to_commands(module, commands): - spec = { - 'command': dict(key=True), - 'prompt': dict(), - 'answer': dict() - } - transform = ComplexList(spec, module) - return transform(commands) - - -def run_commands(module, commands, check_rc=True): - responses = list() - connection = get_connection(module) - - for cmd in to_list(commands): - if isinstance(cmd, dict): - command = cmd['command'] - prompt = cmd['prompt'] - answer = cmd['answer'] - else: - command = cmd - prompt = None - answer = None - - try: - out = connection.get(command, prompt, answer) - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - try: - out = to_text(out, errors='surrogate_or_strict') - except UnicodeError: - module.fail_json( - msg=u'Failed to decode output from %s: %s' % (cmd, to_text(out))) - - responses.append(out) - - return responses - - -def load_config(module, commands): - connection = get_connection(module) - - out = connection.edit_config(commands) diff --git a/plugins/modules/cp_publish.py b/plugins/modules/cp_publish.py deleted file mode 120000 index 76f82d7c..00000000 --- a/plugins/modules/cp_publish.py +++ /dev/null @@ -1 +0,0 @@ -./network/check_point/cp_publish.py \ No newline at end of file diff --git a/plugins/modules/network/avi/avi_useraccount.py b/plugins/modules/network/avi/avi_useraccount.py index b37629b3..9d3f4c2f 100644 --- a/plugins/modules/network/avi/avi_useraccount.py +++ b/plugins/modules/network/avi/avi_useraccount.py @@ -44,6 +44,7 @@ description: - If specifically set to true then old password is tried first for controller and then the new password is tried. If not specified this flag then the new password is tried first. + default: false extends_documentation_fragment: - community.network.avi diff --git a/plugins/modules/network/check_point/cp_publish.py b/plugins/modules/network/check_point/cp_publish.py deleted file mode 100644 index 27a0c7ca..00000000 --- a/plugins/modules/network/check_point/cp_publish.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage Check Point Firewall (c) 2019 -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) - -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: cp_publish -short_description: All the changes done by this user will be seen by all users only after publish is called. -description: - - All the changes done by this user will be seen by all users only after publish is called. - All operations are performed over Web Services API. -author: "Or Soffer (@chkp-orso)" -options: - uid: - description: - - Session unique identifier. Specify it to publish a different session than the one you currently use. - type: str -extends_documentation_fragment: -- check_point.mgmt.checkpoint_commands - -''' - -EXAMPLES = """ -- name: Publish - community.network.cp_publish: -""" - -RETURN = """ -cp_publish: - description: The checkpoint publish output. - returned: always. - type: dict -""" - -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.check_point.mgmt.plugins.module_utils.checkpoint import checkpoint_argument_spec_for_commands, api_command - - -def main(): - argument_spec = dict( - uid=dict(type='str') - ) - argument_spec.update(checkpoint_argument_spec_for_commands) - - module = AnsibleModule(argument_spec=argument_spec) - - command = "publish" - - result = api_command(module, command) - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/cloudengine/ce_multicast_igmp_enable.py b/plugins/modules/network/cloudengine/ce_multicast_igmp_enable.py index fb550d24..1432f19a 100644 --- a/plugins/modules/network/cloudengine/ce_multicast_igmp_enable.py +++ b/plugins/modules/network/cloudengine/ce_multicast_igmp_enable.py @@ -45,6 +45,7 @@ description: - Enable Layer 2 multicast Snooping in a VLAN. type: bool + default: false version: description: - Specifies the IGMP version that can be processed. @@ -54,6 +55,7 @@ description: - Layer 2 multicast snooping proxy is enabled. type: bool + default: false state: description: - Specify desired state of the resource. diff --git a/plugins/modules/network/cnos/cnos_static_route.py b/plugins/modules/network/cnos/cnos_static_route.py index 53f0d9f4..2757e543 100644 --- a/plugins/modules/network/cnos/cnos_static_route.py +++ b/plugins/modules/network/cnos/cnos_static_route.py @@ -112,14 +112,19 @@ """ from copy import deepcopy from re import findall -from ansible_collections.ansible.netcommon.plugins.module_utils.compat import ipaddress -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import validate_ip_address from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import remove_default_spec from ansible_collections.community.network.plugins.module_utils.network.cnos.cnos import get_config, load_config from ansible_collections.community.network.plugins.module_utils.network.cnos.cnos import check_args from ansible_collections.community.network.plugins.module_utils.network.cnos.cnos import cnos_argument_spec +try: + import ipaddress + HAS_IPADDRESS = True +except ImportError: + HAS_IPADDRESS = False + def map_obj_to_commands(want, have): commands = list() @@ -259,6 +264,8 @@ def main(): required_one_of=required_one_of, mutually_exclusive=mutually_exclusive, supports_check_mode=True) + if not HAS_IPADDRESS: + module.fail_json(msg=missing_required_lib("ipaddress")) warnings = list() check_args(module, warnings) diff --git a/plugins/modules/network/icx/icx_banner.py b/plugins/modules/network/icx/icx_banner.py index 71c92524..f3ba4d0c 100644 --- a/plugins/modules/network/icx/icx_banner.py +++ b/plugins/modules/network/icx/icx_banner.py @@ -41,8 +41,8 @@ description: - Specifies whether or not the motd configuration should accept the require-enter-key + - Default is false. type: bool - default: no check_running_config: description: - Check running configuration. This can be set as environment variable. diff --git a/plugins/modules/network/icx/icx_interface.py b/plugins/modules/network/icx/icx_interface.py index d483b72f..df18a5ae 100644 --- a/plugins/modules/network/icx/icx_interface.py +++ b/plugins/modules/network/icx/icx_interface.py @@ -107,7 +107,7 @@ enabled: description: - "enable/disable the poe of the given interface C(name)" - default: no + - "Default is false." type: bool aggregate: description: diff --git a/plugins/modules/network/icx/icx_user.py b/plugins/modules/network/icx/icx_user.py index 6cb6a041..8cd5f6c0 100644 --- a/plugins/modules/network/icx/icx_user.py +++ b/plugins/modules/network/icx/icx_user.py @@ -105,6 +105,7 @@ a password. This will allow the user to login to the system without being authenticated by a password. type: bool + default: false purge: description: - If set to true module will remove any previously diff --git a/plugins/modules/network/ingate/ig_config.py b/plugins/modules/network/ingate/ig_config.py index 46cf2e9d..0abc5ec7 100644 --- a/plugins/modules/network/ingate/ig_config.py +++ b/plugins/modules/network/ingate/ig_config.py @@ -65,6 +65,7 @@ - Expect no response when storing the preliminary configuration. Refer to the C(store) option. type: bool + default: false return_rowid: description: - Get rowid(s) from a table where the columns match. diff --git a/plugins/modules/network/netvisor/pn_cluster.py b/plugins/modules/network/netvisor/pn_cluster.py deleted file mode 100644 index c0d43802..00000000 --- a/plugins/modules/network/netvisor/pn_cluster.py +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/python -""" PN CLI cluster-create/cluster-delete """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_cluster -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to create/delete a cluster. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute cluster-create or cluster-delete command. - - A cluster allows two switches to cooperate in high-availability (HA) - deployments. The nodes that form the cluster must be members of the same - fabric. Clusters are typically used in conjunction with a virtual link - aggregation group (VLAG) that allows links physically connected to two - separate switches appear as a single trunk to a third device. The third - device can be a switch,server, or any Ethernet device. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch to run the cli on. - required: False - default: 'local' - state: - description: - - Specify action to perform. Use 'present' to create cluster and 'absent' - to delete cluster. - required: true - choices: ['present', 'absent'] - pn_name: - description: - - Specify the name of the cluster. - required: true - pn_cluster_node1: - description: - - Specify the name of the first switch in the cluster. - - Required for 'cluster-create'. - pn_cluster_node2: - description: - - Specify the name of the second switch in the cluster. - - Required for 'cluster-create'. - pn_validate: - description: - - Validate the inter-switch links and state of switches in the cluster. - type: bool -''' - -EXAMPLES = """ -- name: Create spine cluster - community.network.pn_cluster: - state: 'present' - pn_name: 'spine-cluster' - pn_cluster_node1: 'spine01' - pn_cluster_node2: 'spine02' - pn_validate: True - pn_quiet: True - -- name: Delete spine cluster - community.network.pn_cluster: - state: 'absent' - pn_name: 'spine-cluster' - pn_quiet: True -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the cluster command. - returned: always - type: list -stderr: - description: The set of error responses from the cluster command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - -NAME_EXISTS = None -NODE1_EXISTS = None -NODE2_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks for idempotency using the cluster-show command. - If a cluster with given name exists, return NAME_EXISTS as True else False. - If the given cluster-node-1 is already a part of another cluster, return - NODE1_EXISTS as True else False. - If the given cluster-node-2 is already a part of another cluster, return - NODE2_EXISTS as True else False. - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: NAME_EXISTS, NODE1_EXISTS, NODE2_EXISTS - """ - name = module.params['pn_name'] - node1 = module.params['pn_cluster_node1'] - node2 = module.params['pn_cluster_node2'] - - show = cli + ' cluster-show format name,cluster-node-1,cluster-node-2 ' - show = shlex.split(show) - out = module.run_command(show)[1] - - out = out.split() - # Global flags - global NAME_EXISTS, NODE1_EXISTS, NODE2_EXISTS - - if name in out: - NAME_EXISTS = True - else: - NAME_EXISTS = False - if node1 in out: - NODE1_EXISTS = True - else: - NODE2_EXISTS = False - if node2 in out: - NODE2_EXISTS = True - else: - NODE2_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'cluster-create' - if state == 'absent': - command = 'cluster-delete' - return command - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent']), - pn_name=dict(required=True, type='str'), - pn_cluster_node1=dict(type='str'), - pn_cluster_node2=dict(type='str'), - pn_validate=dict(type='bool') - ), - required_if=( - ["state", "present", - ["pn_name", "pn_cluster_node1", "pn_cluster_node2"]], - ["state", "absent", ["pn_name"]] - ) - ) - - # Accessing the parameters - state = module.params['state'] - name = module.params['pn_name'] - cluster_node1 = module.params['pn_cluster_node1'] - cluster_node2 = module.params['pn_cluster_node2'] - validate = module.params['pn_validate'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if command == 'cluster-create': - - check_cli(module, cli) - - if NAME_EXISTS is True: - module.exit_json( - skipped=True, - msg='Cluster with name %s already exists' % name - ) - if NODE1_EXISTS is True: - module.exit_json( - skipped=True, - msg='Node %s already part of a cluster' % cluster_node1 - ) - if NODE2_EXISTS is True: - module.exit_json( - skipped=True, - msg='Node %s already part of a cluster' % cluster_node2 - ) - - cli += ' %s name %s ' % (command, name) - cli += 'cluster-node-1 %s cluster-node-2 %s ' % (cluster_node1, - cluster_node2) - if validate is True: - cli += ' validate ' - if validate is False: - cli += ' no-validate ' - - if command == 'cluster-delete': - - check_cli(module, cli) - - if NAME_EXISTS is False: - module.exit_json( - skipped=True, - msg='Cluster with name %s does not exist' % name - ) - cli += ' %s name %s ' % (command, name) - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_ospf.py b/plugins/modules/network/netvisor/pn_ospf.py deleted file mode 100644 index 4ee2567e..00000000 --- a/plugins/modules/network/netvisor/pn_ospf.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/usr/bin/python -""" PN-CLI vrouter-ospf-add/remove """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_ospf -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to add/remove ospf protocol to a vRouter. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-ospf-add, vrouter-ospf-remove command. - - This command adds/removes Open Shortest Path First(OSPF) routing - protocol to a virtual router(vRouter) service. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch to run the CLI on. - required: False - default: 'local' - state: - description: - - Assert the state of the ospf. Use 'present' to add ospf - and 'absent' to remove ospf. - required: True - default: present - choices: ['present', 'absent'] - pn_vrouter_name: - description: - - Specify the name of the vRouter. - required: True - pn_network_ip: - description: - - Specify the network IP (IPv4 or IPv6) address. - required: True - pn_ospf_area: - description: - - Stub area number for the configuration. Required for vrouter-ospf-add. -''' - -EXAMPLES = """ -- name: "Add OSPF to vrouter" - community.network.pn_ospf: - state: present - pn_vrouter_name: name-string - pn_network_ip: 192.168.11.2/24 - pn_ospf_area: 1.0.0.0 - -- name: "Remove OSPF from vrouter" - community.network.pn_ospf: - state: absent - pn_vrouter_name: name-string -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the ospf command. - returned: always - type: list -stderr: - description: The set of error responses from the ospf command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - -VROUTER_EXISTS = None -NETWORK_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks if vRouter exists on the target node. - This method also checks for idempotency using the vrouter-ospf-show command. - If the given vRouter exists, return VROUTER_EXISTS as True else False. - If an OSPF network with the given ip exists on the given vRouter, - return NETWORK_EXISTS as True else False. - - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VROUTER_EXISTS, NETWORK_EXISTS - """ - vrouter_name = module.params['pn_vrouter_name'] - network_ip = module.params['pn_network_ip'] - # Global flags - global VROUTER_EXISTS, NETWORK_EXISTS - - # Check for vRouter - check_vrouter = cli + ' vrouter-show format name no-show-headers ' - check_vrouter = shlex.split(check_vrouter) - out = module.run_command(check_vrouter)[1] - out = out.split() - - if vrouter_name in out: - VROUTER_EXISTS = True - else: - VROUTER_EXISTS = False - - # Check for OSPF networks - show = cli + ' vrouter-ospf-show vrouter-name %s ' % vrouter_name - show += 'format network no-show-headers' - show = shlex.split(show) - out = module.run_command(show)[1] - out = out.split() - - if network_ip in out: - NETWORK_EXISTS = True - else: - NETWORK_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - cmd = shlex.split(cli) - - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-ospf-add' - if state == 'absent': - command = 'vrouter-ospf-remove' - return command - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(type='str', default='present', choices=['present', - 'absent']), - pn_vrouter_name=dict(required=True, type='str'), - pn_network_ip=dict(required=True, type='str'), - pn_ospf_area=dict(type='str') - ), - required_if=( - ['state', 'present', - ['pn_network_ip', 'pn_ospf_area']], - ['state', 'absent', ['pn_network_ip']] - ) - ) - - # Accessing the arguments - state = module.params['state'] - vrouter_name = module.params['pn_vrouter_name'] - network_ip = module.params['pn_network_ip'] - ospf_area = module.params['pn_ospf_area'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - check_cli(module, cli) - - if state == 'present': - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if NETWORK_EXISTS is True: - module.exit_json( - skipped=True, - msg=('OSPF with network ip %s already exists on %s' - % (network_ip, vrouter_name)) - ) - cli += (' %s vrouter-name %s network %s ospf-area %s' - % (command, vrouter_name, network_ip, ospf_area)) - - if state == 'absent': - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if NETWORK_EXISTS is False: - module.exit_json( - skipped=True, - msg=('OSPF with network ip %s already exists on %s' - % (network_ip, vrouter_name)) - ) - cli += (' %s vrouter-name %s network %s' - % (command, vrouter_name, network_ip)) - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_ospfarea.py b/plugins/modules/network/netvisor/pn_ospfarea.py deleted file mode 100644 index 305b9649..00000000 --- a/plugins/modules/network/netvisor/pn_ospfarea.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/python -""" PN-CLI vrouter-ospf-add/remove """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_ospfarea -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to add/remove ospf area to/from a vrouter. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-ospf-add, vrouter-ospf-remove command. - - This command adds/removes Open Shortest Path First(OSPF) area to/from - a virtual router(vRouter) service. -options: - pn_cliusername: - description: - - Login username. - required: true - pn_clipassword: - description: - - Login password. - required: true - pn_cliswitch: - description: - - Target switch(es) to run the CLI on. - required: False - state: - description: - - State the action to perform. Use 'present' to add ospf-area, 'absent' - to remove ospf-area and 'update' to modify ospf-area. - required: true - choices: ['present', 'absent', 'update'] - pn_vrouter_name: - description: - - Specify the name of the vRouter. - required: true - pn_ospf_area: - description: - - Specify the OSPF area number. - required: true - pn_stub_type: - description: - - Specify the OSPF stub type. - choices: ['none', 'stub', 'stub-no-summary', 'nssa', 'nssa-no-summary'] - pn_prefix_listin: - description: - - OSPF prefix list for filtering incoming packets. - pn_prefix_listout: - description: - - OSPF prefix list for filtering outgoing packets. - pn_quiet: - description: - - Enable/disable system information. - required: false - type: bool - default: true -''' - -EXAMPLES = """ -- name: "Add OSPF area to vrouter" - community.network.pn_ospfarea: - state: present - pn_cliusername: admin - pn_clipassword: admin - pn_ospf_area: 1.0.0.0 - pn_stub_type: stub - -- name: "Remove OSPF from vrouter" - pn_ospf: - state: absent - pn_cliusername: admin - pn_clipassword: admin - pn_vrouter_name: name-string - pn_ospf_area: 1.0.0.0 -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the ospf command. - returned: always - type: list -stderr: - description: The set of error responses from the ospf command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-ospf-area-add' - if state == 'absent': - command = 'vrouter-ospf-area-remove' - if state == 'update': - command = 'vrouter-ospf-area-modify' - return command - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=True, type='str'), - pn_clipassword=dict(required=True, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_vrouter_name=dict(required=True, type='str'), - pn_ospf_area=dict(required=True, type='str'), - pn_stub_type=dict(type='str', choices=['none', 'stub', 'nssa', - 'stub-no-summary', - 'nssa-no-summary']), - pn_prefix_listin=dict(type='str'), - pn_prefix_listout=dict(type='str'), - pn_quiet=dict(type='bool', default='True') - ) - ) - - # Accessing the arguments - cliusername = module.params['pn_cliusername'] - clipassword = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - vrouter_name = module.params['pn_vrouter_name'] - ospf_area = module.params['pn_ospf_area'] - stub_type = module.params['pn_stub_type'] - prefix_listin = module.params['pn_prefix_listin'] - prefix_listout = module.params['pn_prefix_listout'] - quiet = module.params['pn_quiet'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = '/usr/bin/cli' - - if quiet is True: - cli += ' --quiet ' - - cli += ' --user %s:%s ' % (cliusername, clipassword) - - if cliswitch: - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - - cli += ' %s vrouter-name %s area %s ' % (command, vrouter_name, ospf_area) - - if stub_type: - cli += ' stub-type ' + stub_type - - if prefix_listin: - cli += ' prefix-list-in ' + prefix_listin - - if prefix_listout: - cli += ' prefix-list-out ' + prefix_listout - - # Run the CLI command - ospfcommand = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(ospfcommand) - - # Response in JSON format - if result != 0: - module.exit_json( - command=cli, - stderr=err.rstrip("\r\n"), - changed=False - ) - - else: - module.exit_json( - command=cli, - stdout=out.rstrip("\r\n"), - changed=True - ) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_show.py b/plugins/modules/network/netvisor/pn_show.py deleted file mode 100644 index 6de9d250..00000000 --- a/plugins/modules/network/netvisor/pn_show.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/python -""" PN CLI show commands """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_show -author: "Pluribus Networks (@amitsi)" -short_description: Run show commands on nvOS device. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute show command in the nodes and returns the results - read from the device. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the cli on. - required: False - pn_command: - description: - - The C(pn_command) takes a CLI show command as value. - required: true - pn_parameters: - description: - - Display output using a specific parameter. Use 'all' to display - possible output. List of comma separated parameters. - default: 'all' - pn_options: - description: - - Specify formatting options. -''' - -EXAMPLES = """ -- name: Run the vlan-show command - community.network.pn_show: - pn_command: 'vlan-show' - pn_parameters: id,scope,ports - pn_options: 'layout vertical' - -- name: Run the vlag-show command - community.network.pn_show: - pn_command: 'vlag-show' - pn_parameters: 'id,name,cluster,mode' - pn_options: 'no-show-headers' - -- name: Run the cluster-show command - community.network.pn_show: - pn_command: 'cluster-show' -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the show command. - returned: always - type: list -stderr: - description: The set of error responses from the show command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused any change on the target. - returned: always(False) - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch: - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - command = module.params['pn_command'] - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - msg='%s: ' % command, - stderr=err.strip(), - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - msg='%s: ' % command, - stdout=out.strip(), - changed=False - ) - - else: - module.exit_json( - command=cli, - msg='%s: Nothing to display!!!' % command, - changed=False - ) - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=True, type='str'), - pn_clipassword=dict(required=True, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str'), - pn_command=dict(required=True, type='str'), - pn_parameters=dict(default='all', type='str'), - pn_options=dict(type='str') - ) - ) - - # Accessing the arguments - command = module.params['pn_command'] - parameters = module.params['pn_parameters'] - options = module.params['pn_options'] - - # Building the CLI command string - cli = pn_cli(module) - - cli += ' %s format %s ' % (command, parameters) - - if options: - cli += options - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_trunk.py b/plugins/modules/network/netvisor/pn_trunk.py deleted file mode 100644 index f7144347..00000000 --- a/plugins/modules/network/netvisor/pn_trunk.py +++ /dev/null @@ -1,462 +0,0 @@ -#!/usr/bin/python -""" PN CLI trunk-create/trunk-delete/trunk-modify """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_trunk -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to create/delete/modify a trunk. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute trunk-create or trunk-delete command. - - Trunks can be used to aggregate network links at Layer 2 on the local - switch. Use this command to create a new trunk. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the cli on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to create trunk, - 'absent' to delete trunk and 'update' to modify trunk. - required: True - choices: ['present', 'absent', 'update'] - pn_name: - description: - - Specify the name for the trunk configuration. - required: true - pn_ports: - description: - - Specify the port number(s) for the link(s) to aggregate into the trunk. - - Required for trunk-create. - pn_speed: - description: - - Specify the port speed or disable the port. - choices: ['disable', '10m', '100m', '1g', '2.5g', '10g', '40g'] - pn_egress_rate_limit: - description: - - Specify an egress port data rate limit for the configuration. - pn_jumbo: - description: - - Specify if the port can receive jumbo frames. - type: bool - pn_lacp_mode: - description: - - Specify the LACP mode for the configuration. - choices: ['off', 'passive', 'active'] - pn_lacp_priority: - description: - - Specify the LACP priority. This is a number between 1 and 65535 with a - default value of 32768. - pn_lacp_timeout: - description: - - Specify the LACP time out as slow (30 seconds) or fast (4seconds). - The default value is slow. - choices: ['slow', 'fast'] - pn_lacp_fallback: - description: - - Specify the LACP fallback mode as bundles or individual. - choices: ['bundle', 'individual'] - pn_lacp_fallback_timeout: - description: - - Specify the LACP fallback timeout in seconds. The range is between 30 - and 60 seconds with a default value of 50 seconds. - pn_edge_switch: - description: - - Specify if the switch is an edge switch. - type: bool - pn_pause: - description: - - Specify if pause frames are sent. - type: bool - pn_description: - description: - - Specify a description for the trunk configuration. - pn_loopback: - description: - - Specify loopback if you want to use loopback. - type: bool - pn_mirror_receive: - description: - - Specify if the configuration receives mirrored traffic. - type: bool - pn_unknown_ucast_level: - description: - - Specify an unknown unicast level in percent. The default value is 100%. - pn_unknown_mcast_level: - description: - - Specify an unknown multicast level in percent. The default value is 100%. - pn_broadcast_level: - description: - - Specify a broadcast level in percent. The default value is 100%. - pn_port_macaddr: - description: - - Specify the MAC address of the port. - pn_loopvlans: - description: - - Specify a list of looping vlans. - pn_routing: - description: - - Specify if the port participates in routing on the network. - type: bool - pn_host: - description: - - Host facing port control setting. - type: bool -''' - -EXAMPLES = """ -- name: Create trunk - community.network.pn_trunk: - state: 'present' - pn_name: 'spine-to-leaf' - pn_ports: '11,12,13,14' - -- name: Delete trunk - community.network.pn_trunk: - state: 'absent' - pn_name: 'spine-to-leaf' -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the trunk command. - returned: always - type: list -stderr: - description: The set of error responses from the trunk command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# Ansible boiler-plate -from ansible.module_utils.basic import AnsibleModule - -TRUNK_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks for idempotency using the trunk-show command. - If a trunk with given name exists, return TRUNK_EXISTS as True else False. - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: TRUNK_EXISTS - """ - name = module.params['pn_name'] - - show = cli + ' trunk-show format switch,name no-show-headers' - show = shlex.split(show) - out = module.run_command(show)[1] - - out = out.split() - # Global flags - global TRUNK_EXISTS - if name in out: - TRUNK_EXISTS = True - else: - TRUNK_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'trunk-create' - if state == 'absent': - command = 'trunk-delete' - if state == 'update': - command = 'trunk-modify' - return command - - -def main(): - """ This portion is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_name=dict(required=True, type='str'), - pn_ports=dict(type='str'), - pn_speed=dict(type='str', - choices=['disable', '10m', '100m', '1g', '2.5g', - '10g', '40g']), - pn_egress_rate_limit=dict(type='str'), - pn_jumbo=dict(type='bool'), - pn_lacp_mode=dict(type='str', choices=[ - 'off', 'passive', 'active']), - pn_lacp_priority=dict(type='int'), - pn_lacp_timeout=dict(type='str', choices=['slow', 'fast']), - pn_lacp_fallback=dict(type='str', choices=[ - 'bundle', 'individual']), - pn_lacp_fallback_timeout=dict(type='str'), - pn_edge_switch=dict(type='bool'), - pn_pause=dict(type='bool'), - pn_description=dict(type='str'), - pn_loopback=dict(type='bool'), - pn_mirror_receive=dict(type='bool'), - pn_unknown_ucast_level=dict(type='str'), - pn_unknown_mcast_level=dict(type='str'), - pn_broadcast_level=dict(type='str'), - pn_port_macaddr=dict(type='str'), - pn_loopvlans=dict(type='str'), - pn_routing=dict(type='bool'), - pn_host=dict(type='bool') - ), - required_if=( - ["state", "present", ["pn_name", "pn_ports"]], - ["state", "absent", ["pn_name"]], - ["state", "update", ["pn_name"]] - ) - ) - - # Accessing the arguments - state = module.params['state'] - name = module.params['pn_name'] - ports = module.params['pn_ports'] - speed = module.params['pn_speed'] - egress_rate_limit = module.params['pn_egress_rate_limit'] - jumbo = module.params['pn_jumbo'] - lacp_mode = module.params['pn_lacp_mode'] - lacp_priority = module.params['pn_lacp_priority'] - lacp_timeout = module.params['pn_lacp_timeout'] - lacp_fallback = module.params['pn_lacp_fallback'] - lacp_fallback_timeout = module.params['pn_lacp_fallback_timeout'] - edge_switch = module.params['pn_edge_switch'] - pause = module.params['pn_pause'] - description = module.params['pn_description'] - loopback = module.params['pn_loopback'] - mirror_receive = module.params['pn_mirror_receive'] - unknown_ucast_level = module.params['pn_unknown_ucast_level'] - unknown_mcast_level = module.params['pn_unknown_mcast_level'] - broadcast_level = module.params['pn_broadcast_level'] - port_macaddr = module.params['pn_port_macaddr'] - loopvlans = module.params['pn_loopvlans'] - routing = module.params['pn_routing'] - host = module.params['pn_host'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if command == 'trunk-delete': - - check_cli(module, cli) - if TRUNK_EXISTS is False: - module.exit_json( - skipped=True, - msg='Trunk with name %s does not exist' % name - ) - cli += ' %s name %s ' % (command, name) - - else: - if command == 'trunk-create': - check_cli(module, cli) - if TRUNK_EXISTS is True: - module.exit_json( - skipped=True, - msg='Trunk with name %s already exists' % name - ) - cli += ' %s name %s ' % (command, name) - - # Appending options - if ports: - cli += ' ports ' + ports - - if speed: - cli += ' speed ' + speed - - if egress_rate_limit: - cli += ' egress-rate-limit ' + egress_rate_limit - - if jumbo is True: - cli += ' jumbo ' - if jumbo is False: - cli += ' no-jumbo ' - - if lacp_mode: - cli += ' lacp-mode ' + lacp_mode - - if lacp_priority: - cli += ' lacp-priority ' + lacp_priority - - if lacp_timeout: - cli += ' lacp-timeout ' + lacp_timeout - - if lacp_fallback: - cli += ' lacp-fallback ' + lacp_fallback - - if lacp_fallback_timeout: - cli += ' lacp-fallback-timeout ' + lacp_fallback_timeout - - if edge_switch is True: - cli += ' edge-switch ' - if edge_switch is False: - cli += ' no-edge-switch ' - - if pause is True: - cli += ' pause ' - if pause is False: - cli += ' no-pause ' - - if description: - cli += ' description ' + description - - if loopback is True: - cli += ' loopback ' - if loopback is False: - cli += ' no-loopback ' - - if mirror_receive is True: - cli += ' mirror-receive-only ' - if mirror_receive is False: - cli += ' no-mirror-receive-only ' - - if unknown_ucast_level: - cli += ' unknown-ucast-level ' + unknown_ucast_level - - if unknown_mcast_level: - cli += ' unknown-mcast-level ' + unknown_mcast_level - - if broadcast_level: - cli += ' broadcast-level ' + broadcast_level - - if port_macaddr: - cli += ' port-mac-address ' + port_macaddr - - if loopvlans: - cli += ' loopvlans ' + loopvlans - - if routing is True: - cli += ' routing ' - if routing is False: - cli += ' no-routing ' - - if host is True: - cli += ' host-enable ' - if host is False: - cli += ' host-disable ' - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vlag.py b/plugins/modules/network/netvisor/pn_vlag.py deleted file mode 100644 index 6df7b52e..00000000 --- a/plugins/modules/network/netvisor/pn_vlag.py +++ /dev/null @@ -1,350 +0,0 @@ -#!/usr/bin/python -""" PN CLI vlag-create/vlag-delete/vlag-modify """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vlag -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to create/delete/modify vlag. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vlag-create/vlag-delete/vlag-modify command. - - A virtual link aggregation group (VLAG) allows links that are physically - connected to two different Pluribus Networks devices to appear as a single - trunk to a third device. The third device can be a switch, server, or any - Ethernet device. A VLAG can provide Layer 2 multipathing, which allows you - to create redundancy by increasing bandwidth, enabling multiple parallel - paths between nodes and loadbalancing traffic where alternative paths exist. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run this command on. - default: 'local' - state: - description: - - State the action to perform. Use 'present' to create vlag, - 'absent' to delete vlag and 'update' to modify vlag. - required: True - choices: ['present', 'absent', 'update'] - pn_name: - description: - - The C(pn_name) takes a valid name for vlag configuration. - required: true - pn_port: - description: - - Specify the local VLAG port. - - Required for vlag-create. - pn_peer_port: - description: - - Specify the peer VLAG port. - - Required for vlag-create. - pn_mode: - description: - - Specify the mode for the VLAG. Active-standby indicates one side is - active and the other side is in standby mode. Active-active indicates - that both sides of the vlag are up by default. - choices: ['active-active', 'active-standby'] - pn_peer_switch: - description: - - Specify the fabric-name of the peer switch. - pn_failover_action: - description: - - Specify the failover action as move or ignore. - choices: ['move', 'ignore'] - pn_lacp_mode: - description: - - Specify the LACP mode. - choices: ['off', 'passive', 'active'] - pn_lacp_timeout: - description: - - Specify the LACP timeout as slow(30 seconds) or fast(4 seconds). - choices: ['slow', 'fast'] - pn_lacp_fallback: - description: - - Specify the LACP fallback mode as bundles or individual. - choices: ['bundle', 'individual'] - pn_lacp_fallback_timeout: - description: - - Specify the LACP fallback timeout in seconds. The range is between 30 - and 60 seconds with a default value of 50 seconds. -''' - -EXAMPLES = """ -- name: Create a VLAG - community.network.pn_vlag: - state: 'present' - pn_name: spine-to-leaf - pn_port: 'spine01-to-leaf' - pn_peer_port: 'spine02-to-leaf' - pn_peer_switch: spine02 - pn_mode: 'active-active' - -- name: Delete VLAGs - community.network.pn_vlag: - state: 'absent' - pn_name: spine-to-leaf -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vlag command. - returned: always - type: list -stderr: - description: The set of error responses from the vlag command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - -VLAG_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks for idempotency using the vlag-show command. - If a vlag with given vlag exists, return VLAG_EXISTS as True else False. - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VLAG_EXISTS - """ - name = module.params['pn_name'] - - show = cli + ' vlag-show format name no-show-headers' - show = shlex.split(show) - out = module.run_command(show)[1] - - out = out.split() - # Global flags - global VLAG_EXISTS - if name in out: - VLAG_EXISTS = True - else: - VLAG_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vlag-create' - if state == 'absent': - command = 'vlag-delete' - if state == 'update': - command = 'vlag-modify' - return command - - -def main(): - """ This section is for argument parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_name=dict(required=True, type='str'), - pn_port=dict(type='str'), - pn_peer_port=dict(type='str'), - pn_mode=dict(type='str', choices=[ - 'active-standby', 'active-active']), - pn_peer_switch=dict(type='str'), - pn_failover_action=dict(type='str', choices=['move', 'ignore']), - pn_lacp_mode=dict(type='str', choices=[ - 'off', 'passive', 'active']), - pn_lacp_timeout=dict(type='str', choices=['slow', 'fast']), - pn_lacp_fallback=dict(type='str', choices=[ - 'bundle', 'individual']), - pn_lacp_fallback_timeout=dict(type='str') - ), - required_if=( - ["state", "present", ["pn_name", "pn_port", "pn_peer_port", - "pn_peer_switch"]], - ["state", "absent", ["pn_name"]], - ["state", "update", ["pn_name"]] - ) - ) - - # Argument accessing - state = module.params['state'] - name = module.params['pn_name'] - port = module.params['pn_port'] - peer_port = module.params['pn_peer_port'] - mode = module.params['pn_mode'] - peer_switch = module.params['pn_peer_switch'] - failover_action = module.params['pn_failover_action'] - lacp_mode = module.params['pn_lacp_mode'] - lacp_timeout = module.params['pn_lacp_timeout'] - lacp_fallback = module.params['pn_lacp_fallback'] - lacp_fallback_timeout = module.params['pn_lacp_fallback_timeout'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if command == 'vlag-delete': - - check_cli(module, cli) - if VLAG_EXISTS is False: - module.exit_json( - skipped=True, - msg='VLAG with name %s does not exist' % name - ) - cli += ' %s name %s ' % (command, name) - - else: - - if command == 'vlag-create': - check_cli(module, cli) - if VLAG_EXISTS is True: - module.exit_json( - skipped=True, - msg='VLAG with name %s already exists' % name - ) - cli += ' %s name %s ' % (command, name) - - if port: - cli += ' port %s peer-port %s ' % (port, peer_port) - - if mode: - cli += ' mode ' + mode - - if peer_switch: - cli += ' peer-switch ' + peer_switch - - if failover_action: - cli += ' failover-' + failover_action + '-L2 ' - - if lacp_mode: - cli += ' lacp-mode ' + lacp_mode - - if lacp_timeout: - cli += ' lacp-timeout ' + lacp_timeout - - if lacp_fallback: - cli += ' lacp-fallback ' + lacp_fallback - - if lacp_fallback_timeout: - cli += ' lacp-fallback-timeout ' + lacp_fallback_timeout - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vlan.py b/plugins/modules/network/netvisor/pn_vlan.py deleted file mode 100644 index ce0d55fb..00000000 --- a/plugins/modules/network/netvisor/pn_vlan.py +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/python -""" PN CLI vlan-create/vlan-delete """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vlan -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to create/delete a VLAN. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vlan-create or vlan-delete command. - - VLANs are used to isolate network traffic at Layer 2.The VLAN identifiers - 0 and 4095 are reserved and cannot be used per the IEEE 802.1Q standard. - The range of configurable VLAN identifiers is 2 through 4092. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the cli on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to create vlan and - 'absent' to delete vlan. - required: True - choices: ['present', 'absent'] - pn_vlanid: - description: - - Specify a VLAN identifier for the VLAN. This is a value between - 2 and 4092. - required: True - pn_scope: - description: - - Specify a scope for the VLAN. - - Required for vlan-create. - choices: ['fabric', 'local'] - pn_description: - description: - - Specify a description for the VLAN. - pn_stats: - description: - - Specify if you want to collect statistics for a VLAN. Statistic - collection is enabled by default. - type: bool - pn_ports: - description: - - Specifies the switch network data port number, list of ports, or range - of ports. Port numbers must ne in the range of 1 to 64. - pn_untagged_ports: - description: - - Specifies the ports that should have untagged packets mapped to the - VLAN. Untagged packets are packets that do not contain IEEE 802.1Q VLAN - tags. -''' - -EXAMPLES = """ -- name: Create a VLAN - community.network.pn_vlan: - state: 'present' - pn_vlanid: 1854 - pn_scope: fabric - -- name: Delete VLANs - community.network.pn_vlan: - state: 'absent' - pn_vlanid: 1854 -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vlan command. - returned: always - type: list -stderr: - description: The set of error responses from the vlan command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - -VLAN_EXISTS = None -MAX_VLAN_ID = 4092 -MIN_VLAN_ID = 2 - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks for idempotency using the vlan-show command. - If a vlan with given vlan id exists, return VLAN_EXISTS as True else False. - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VLAN_EXISTS - """ - vlanid = module.params['pn_vlanid'] - - show = cli + \ - ' vlan-show id %s format id,scope no-show-headers' % str(vlanid) - show = shlex.split(show) - out = module.run_command(show)[1] - - out = out.split() - # Global flags - global VLAN_EXISTS - if str(vlanid) in out: - VLAN_EXISTS = True - else: - VLAN_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vlan-create' - if state == 'absent': - command = 'vlan-delete' - return command - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent']), - pn_vlanid=dict(required=True, type='int'), - pn_scope=dict(type='str', choices=['fabric', 'local']), - pn_description=dict(type='str'), - pn_stats=dict(type='bool'), - pn_ports=dict(type='str'), - pn_untagged_ports=dict(type='str') - ), - required_if=( - ["state", "present", ["pn_vlanid", "pn_scope"]], - ["state", "absent", ["pn_vlanid"]] - ) - ) - - # Accessing the arguments - state = module.params['state'] - vlanid = module.params['pn_vlanid'] - scope = module.params['pn_scope'] - description = module.params['pn_description'] - stats = module.params['pn_stats'] - ports = module.params['pn_ports'] - untagged_ports = module.params['pn_untagged_ports'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if not MIN_VLAN_ID <= vlanid <= MAX_VLAN_ID: - module.exit_json( - msg="VLAN id must be between 2 and 4092", - changed=False - ) - - if command == 'vlan-create': - - check_cli(module, cli) - if VLAN_EXISTS is True: - module.exit_json( - skipped=True, - msg='VLAN with id %s already exists' % str(vlanid) - ) - - cli += ' %s id %s scope %s ' % (command, str(vlanid), scope) - - if description: - cli += ' description ' + description - - if stats is True: - cli += ' stats ' - if stats is False: - cli += ' no-stats ' - - if ports: - cli += ' ports ' + ports - - if untagged_ports: - cli += ' untagged-ports ' + untagged_ports - - if command == 'vlan-delete': - - check_cli(module, cli) - if VLAN_EXISTS is False: - module.exit_json( - skipped=True, - msg='VLAN with id %s does not exist' % str(vlanid) - ) - - cli += ' %s id %s ' % (command, str(vlanid)) - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vrouter.py b/plugins/modules/network/netvisor/pn_vrouter.py deleted file mode 100644 index d640d3cd..00000000 --- a/plugins/modules/network/netvisor/pn_vrouter.py +++ /dev/null @@ -1,423 +0,0 @@ -#!/usr/bin/python -""" PN CLI vrouter-create/vrouter-delete/vrouter-modify """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vrouter -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to create/delete/modify a vrouter. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-create, vrouter-delete, vrouter-modify command. - - Each fabric, cluster, standalone switch, or virtual network (VNET) can - provide its tenants with a virtual router (vRouter) service that forwards - traffic between networks and implements Layer 3 protocols. - - C(vrouter-create) creates a new vRouter service. - - C(vrouter-delete) deletes a vRouter service. - - C(vrouter-modify) modifies a vRouter service. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the CLI on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to create vrouter, - 'absent' to delete vrouter and 'update' to modify vrouter. - required: True - choices: ['present', 'absent', 'update'] - pn_name: - description: - - Specify the name of the vRouter. - required: true - pn_vnet: - description: - - Specify the name of the VNET. - - Required for vrouter-create. - pn_service_type: - description: - - Specify if the vRouter is a dedicated or shared VNET service. - choices: ['dedicated', 'shared'] - pn_service_state: - description: - - Specify to enable or disable vRouter service. - choices: ['enable', 'disable'] - pn_router_type: - description: - - Specify if the vRouter uses software or hardware. - - Note that if you specify hardware as router type, you cannot assign IP - addresses using DHCP. You must specify a static IP address. - choices: ['hardware', 'software'] - pn_hw_vrrp_id: - description: - - Specifies the VRRP ID for a hardware vrouter. - pn_router_id: - description: - - Specify the vRouter IP address. - pn_bgp_as: - description: - - Specify the Autonomous System Number(ASN) if the vRouter runs Border - Gateway Protocol(BGP). - pn_bgp_redistribute: - description: - - Specify how BGP routes are redistributed. - choices: ['static', 'connected', 'rip', 'ospf'] - pn_bgp_max_paths: - description: - - Specify the maximum number of paths for BGP. This is a number between - 1 and 255 or 0 to unset. - pn_bgp_options: - description: - - Specify other BGP options as a whitespaces separated string within - single quotes ''. - pn_rip_redistribute: - description: - - Specify how RIP routes are redistributed. - choices: ['static', 'connected', 'ospf', 'bgp'] - pn_ospf_redistribute: - description: - - Specify how OSPF routes are redistributed. - choices: ['static', 'connected', 'bgp', 'rip'] - pn_ospf_options: - description: - - Specify other OSPF options as a whitespaces separated string within - single quotes ''. - pn_vrrp_track_port: - description: - - Specify list of ports and port ranges. -''' - -EXAMPLES = """ -- name: Create vrouter - community.network.pn_vrouter: - state: 'present' - pn_name: 'ansible-vrouter' - pn_vnet: 'ansible-fab-global' - pn_router_id: 208.74.182.1 - -- name: Delete vrouter - community.network.pn_vrouter: - state: 'absent' - pn_name: 'ansible-vrouter' -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vrouter command. - returned: always - type: list -stderr: - description: The set of error responses from the vrouter command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# AnsibleModule boilerplate -from ansible.module_utils.basic import AnsibleModule - -VROUTER_EXISTS = None -VROUTER_NAME_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks for idempotency using the vlan-show command. - A switch can have only one vRouter configuration. - If a vRouter already exists on the given switch, return VROUTER_EXISTS as - True else False. - If a vRouter with the given name exists(on a different switch), return - VROUTER_NAME_EXISTS as True else False. - - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VROUTER_EXISTS, VROUTER_NAME_EXISTS - """ - name = module.params['pn_name'] - # Global flags - global VROUTER_EXISTS, VROUTER_NAME_EXISTS - - # Get the name of the local switch - location = cli + ' switch-setup-show format switch-name' - location = shlex.split(location) - out = module.run_command(location)[1] - location = out.split()[1] - - # Check for any vRouters on the switch - check_vrouter = cli + ' vrouter-show location %s ' % location - check_vrouter += 'format name no-show-headers' - check_vrouter = shlex.split(check_vrouter) - out = module.run_command(check_vrouter)[1] - - if out: - VROUTER_EXISTS = True - else: - VROUTER_EXISTS = False - - # Check for any vRouters with the given name - show = cli + ' vrouter-show format name no-show-headers ' - show = shlex.split(show) - out = module.run_command(show)[1] - out = out.split() - - if name in out: - VROUTER_NAME_EXISTS = True - else: - VROUTER_NAME_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-create' - if state == 'absent': - command = 'vrouter-delete' - if state == 'update': - command = 'vrouter-modify' - return command - - -def main(): - """ This section is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_name=dict(required=True, type='str'), - pn_vnet=dict(type='str'), - pn_service_type=dict(type='str', choices=['dedicated', 'shared']), - pn_service_state=dict(type='str', choices=['enable', 'disable']), - pn_router_type=dict(type='str', choices=['hardware', 'software']), - pn_hw_vrrp_id=dict(type='int'), - pn_router_id=dict(type='str'), - pn_bgp_as=dict(type='int'), - pn_bgp_redistribute=dict(type='str', choices=['static', 'connected', - 'rip', 'ospf']), - pn_bgp_max_paths=dict(type='int'), - pn_bgp_options=dict(type='str'), - pn_rip_redistribute=dict(type='str', choices=['static', 'connected', - 'bgp', 'ospf']), - pn_ospf_redistribute=dict(type='str', choices=['static', 'connected', - 'bgp', 'rip']), - pn_ospf_options=dict(type='str'), - pn_vrrp_track_port=dict(type='str') - ), - required_if=( - ["state", "present", ["pn_name", "pn_vnet"]], - ["state", "absent", ["pn_name"]], - ["state", "update", ["pn_name"]] - ) - ) - - # Accessing the arguments - state = module.params['state'] - name = module.params['pn_name'] - vnet = module.params['pn_vnet'] - service_type = module.params['pn_service_type'] - service_state = module.params['pn_service_state'] - router_type = module.params['pn_router_type'] - hw_vrrp_id = module.params['pn_hw_vrrp_id'] - router_id = module.params['pn_router_id'] - bgp_as = module.params['pn_bgp_as'] - bgp_redistribute = module.params['pn_bgp_redistribute'] - bgp_max_paths = module.params['pn_bgp_max_paths'] - bgp_options = module.params['pn_bgp_options'] - rip_redistribute = module.params['pn_rip_redistribute'] - ospf_redistribute = module.params['pn_ospf_redistribute'] - ospf_options = module.params['pn_ospf_options'] - vrrp_track_port = module.params['pn_vrrp_track_port'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if command == 'vrouter-delete': - check_cli(module, cli) - if VROUTER_NAME_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter with name %s does not exist' % name - ) - cli += ' %s name %s ' % (command, name) - - else: - - if command == 'vrouter-create': - check_cli(module, cli) - if VROUTER_EXISTS is True: - module.exit_json( - skipped=True, - msg='Maximum number of vRouters has been reached on this ' - 'switch' - ) - if VROUTER_NAME_EXISTS is True: - module.exit_json( - skipped=True, - msg='vRouter with name %s already exists' % name - ) - cli += ' %s name %s ' % (command, name) - - if vnet: - cli += ' vnet ' + vnet - - if service_type: - cli += ' %s-vnet-service ' % service_type - - if service_state: - cli += ' ' + service_state - - if router_type: - cli += ' router-type ' + router_type - - if hw_vrrp_id: - cli += ' hw-vrrp-id ' + str(hw_vrrp_id) - - if router_id: - cli += ' router-id ' + router_id - - if bgp_as: - cli += ' bgp-as ' + str(bgp_as) - - if bgp_redistribute: - cli += ' bgp-redistribute ' + bgp_redistribute - - if bgp_max_paths: - cli += ' bgp-max-paths ' + str(bgp_max_paths) - - if bgp_options: - cli += ' %s ' % bgp_options - - if rip_redistribute: - cli += ' rip-redistribute ' + rip_redistribute - - if ospf_redistribute: - cli += ' ospf-redistribute ' + ospf_redistribute - - if ospf_options: - cli += ' %s ' % ospf_options - - if vrrp_track_port: - cli += ' vrrp-track-port ' + vrrp_track_port - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vrouterbgp.py b/plugins/modules/network/netvisor/pn_vrouterbgp.py deleted file mode 100644 index 5e1d4ffa..00000000 --- a/plugins/modules/network/netvisor/pn_vrouterbgp.py +++ /dev/null @@ -1,485 +0,0 @@ -#!/usr/bin/python -""" PN-CLI vrouter-bgp-add/vrouter-bgp-remove/vrouter-bgp-modify """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vrouterbgp -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to add/remove/modify vrouter-bgp. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-bgp-add, vrouter-bgp-remove, vrouter-bgp-modify command. - - Each fabric, cluster, standalone switch, or virtual network (VNET) can - provide its tenants with a vRouter service that forwards traffic between - networks and implements Layer 4 protocols. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the cli on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to add bgp, - 'absent' to remove bgp and 'update' to modify bgp. - required: True - choices: ['present', 'absent', 'update'] - pn_vrouter_name: - description: - - Specify a name for the vRouter service. - required: True - pn_neighbor: - description: - - Specify a neighbor IP address to use for BGP. - - Required for vrouter-bgp-add. - pn_remote_as: - description: - - Specify the remote Autonomous System(AS) number. This value is between - 1 and 4294967295. - - Required for vrouter-bgp-add. - pn_next_hop_self: - description: - - Specify if the next-hop is the same router or not. - type: bool - pn_password: - description: - - Specify a password, if desired. - pn_ebgp: - description: - - Specify a value for external BGP to accept or attempt BGP connections - to external peers, not directly connected, on the network. This is a - value between 1 and 255. - pn_prefix_listin: - description: - - Specify the prefix list to filter traffic inbound. - pn_prefix_listout: - description: - - Specify the prefix list to filter traffic outbound. - pn_route_reflector: - description: - - Specify if a route reflector client is used. - type: bool - pn_override_capability: - description: - - Specify if you want to override capability. - type: bool - pn_soft_reconfig: - description: - - Specify if you want a soft reconfiguration of inbound traffic. - type: bool - pn_max_prefix: - description: - - Specify the maximum number of prefixes. - pn_max_prefix_warn: - description: - - Specify if you want a warning message when the maximum number of - prefixes is exceeded. - type: bool - pn_bfd: - description: - - Specify if you want BFD protocol support for fault detection. - type: bool - pn_multiprotocol: - description: - - Specify a multi-protocol for BGP. - choices: ['ipv4-unicast', 'ipv6-unicast'] - pn_weight: - description: - - Specify a default weight value between 0 and 65535 for the neighbor - routes. - pn_default_originate: - description: - - Specify if you want announce default routes to the neighbor or not. - type: bool - pn_keepalive: - description: - - Specify BGP neighbor keepalive interval in seconds. - pn_holdtime: - description: - - Specify BGP neighbor holdtime in seconds. - pn_route_mapin: - description: - - Specify inbound route map for neighbor. - pn_route_mapout: - description: - - Specify outbound route map for neighbor. -''' - -EXAMPLES = """ -- name: Add vrouter-bgp - community.network.pn_vrouterbgp: - state: 'present' - pn_vrouter_name: 'ansible-vrouter' - pn_neighbor: 104.104.104.1 - pn_remote_as: 1800 - -- name: Remove vrouter-bgp - community.network.pn_vrouterbgp: - state: 'absent' - pn_name: 'ansible-vrouter' -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vrouterbpg command. - returned: always - type: list -stderr: - description: The set of error responses from the vrouterbgp command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# Ansible boiler-plate -from ansible.module_utils.basic import AnsibleModule - -VROUTER_EXISTS = None -NEIGHBOR_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks if vRouter exists on the target node. - This method also checks for idempotency using the vrouter-bgp-show command. - If the given vRouter exists, return VROUTER_EXISTS as True else False. - If a BGP neighbor with the given ip exists on the given vRouter, - return NEIGHBOR_EXISTS as True else False. - - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VROUTER_EXISTS, NEIGHBOR_EXISTS - """ - vrouter_name = module.params['pn_vrouter_name'] - neighbor = module.params['pn_neighbor'] - # Global flags - global VROUTER_EXISTS, NEIGHBOR_EXISTS - - # Check for vRouter - check_vrouter = cli + ' vrouter-show format name no-show-headers ' - check_vrouter = shlex.split(check_vrouter) - out = module.run_command(check_vrouter)[1] - out = out.split() - - if vrouter_name in out: - VROUTER_EXISTS = True - else: - VROUTER_EXISTS = False - - # Check for BGP neighbors - show = cli + ' vrouter-bgp-show vrouter-name %s ' % vrouter_name - show += 'format neighbor no-show-headers' - show = shlex.split(show) - out = module.run_command(show)[1] - out = out.split() - - if neighbor in out: - NEIGHBOR_EXISTS = True - else: - NEIGHBOR_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-bgp-add' - if state == 'absent': - command = 'vrouter-bgp-remove' - if state == 'update': - command = 'vrouter-bgp-modify' - return command - - -def main(): - """ This portion is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_vrouter_name=dict(required=True, type='str'), - pn_neighbor=dict(type='str'), - pn_remote_as=dict(type='str'), - pn_next_hop_self=dict(type='bool'), - pn_password=dict(type='str', no_log=True), - pn_ebgp=dict(type='int'), - pn_prefix_listin=dict(type='str'), - pn_prefix_listout=dict(type='str'), - pn_route_reflector=dict(type='bool'), - pn_override_capability=dict(type='bool'), - pn_soft_reconfig=dict(type='bool'), - pn_max_prefix=dict(type='int'), - pn_max_prefix_warn=dict(type='bool'), - pn_bfd=dict(type='bool'), - pn_multiprotocol=dict(type='str', - choices=['ipv4-unicast', 'ipv6-unicast']), - pn_weight=dict(type='int'), - pn_default_originate=dict(type='bool'), - pn_keepalive=dict(type='str'), - pn_holdtime=dict(type='str'), - pn_route_mapin=dict(type='str'), - pn_route_mapout=dict(type='str') - ), - required_if=( - ["state", "present", - ["pn_vrouter_name", "pn_neighbor", "pn_remote_as"]], - ["state", "absent", - ["pn_vrouter_name", "pn_neighbor"]], - ["state", "update", - ["pn_vrouter_name", "pn_neighbor"]] - ) - ) - - # Accessing the arguments - state = module.params['state'] - vrouter_name = module.params['pn_vrouter_name'] - neighbor = module.params['pn_neighbor'] - remote_as = module.params['pn_remote_as'] - next_hop_self = module.params['pn_next_hop_self'] - password = module.params['pn_password'] - ebgp = module.params['pn_ebgp'] - prefix_listin = module.params['pn_prefix_listin'] - prefix_listout = module.params['pn_prefix_listout'] - route_reflector = module.params['pn_route_reflector'] - override_capability = module.params['pn_override_capability'] - soft_reconfig = module.params['pn_soft_reconfig'] - max_prefix = module.params['pn_max_prefix'] - max_prefix_warn = module.params['pn_max_prefix_warn'] - bfd = module.params['pn_bfd'] - multiprotocol = module.params['pn_multiprotocol'] - weight = module.params['pn_weight'] - default_originate = module.params['pn_default_originate'] - keepalive = module.params['pn_keepalive'] - holdtime = module.params['pn_holdtime'] - route_mapin = module.params['pn_route_mapin'] - route_mapout = module.params['pn_route_mapout'] - - # Building the CLI command string - cli = pn_cli(module) - - command = get_command_from_state(state) - if command == 'vrouter-bgp-remove': - check_cli(module, cli) - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if NEIGHBOR_EXISTS is False: - module.exit_json( - skipped=True, - msg=('BGP neighbor with IP %s does not exist on %s' - % (neighbor, vrouter_name)) - ) - cli += (' %s vrouter-name %s neighbor %s ' - % (command, vrouter_name, neighbor)) - - else: - - if command == 'vrouter-bgp-add': - check_cli(module, cli) - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if NEIGHBOR_EXISTS is True: - module.exit_json( - skipped=True, - msg=('BGP neighbor with IP %s already exists on %s' - % (neighbor, vrouter_name)) - ) - - cli += (' %s vrouter-name %s neighbor %s ' - % (command, vrouter_name, neighbor)) - - if remote_as: - cli += ' remote-as ' + str(remote_as) - - if next_hop_self is True: - cli += ' next-hop-self ' - if next_hop_self is False: - cli += ' no-next-hop-self ' - - if password: - cli += ' password ' + password - - if ebgp: - cli += ' ebgp-multihop ' + str(ebgp) - - if prefix_listin: - cli += ' prefix-list-in ' + prefix_listin - - if prefix_listout: - cli += ' prefix-list-out ' + prefix_listout - - if route_reflector is True: - cli += ' route-reflector-client ' - if route_reflector is False: - cli += ' no-route-reflector-client ' - - if override_capability is True: - cli += ' override-capability ' - if override_capability is False: - cli += ' no-override-capability ' - - if soft_reconfig is True: - cli += ' soft-reconfig-inbound ' - if soft_reconfig is False: - cli += ' no-soft-reconfig-inbound ' - - if max_prefix: - cli += ' max-prefix ' + str(max_prefix) - - if max_prefix_warn is True: - cli += ' max-prefix-warn-only ' - if max_prefix_warn is False: - cli += ' no-max-prefix-warn-only ' - - if bfd is True: - cli += ' bfd ' - if bfd is False: - cli += ' no-bfd ' - - if multiprotocol: - cli += ' multi-protocol ' + multiprotocol - - if weight: - cli += ' weight ' + str(weight) - - if default_originate is True: - cli += ' default-originate ' - if default_originate is False: - cli += ' no-default-originate ' - - if keepalive: - cli += ' neighbor-keepalive-interval ' + keepalive - - if holdtime: - cli += ' neighbor-holdtime ' + holdtime - - if route_mapin: - cli += ' route-map-in ' + route_mapin - - if route_mapout: - cli += ' route-map-out ' + route_mapout - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vrouterif.py b/plugins/modules/network/netvisor/pn_vrouterif.py deleted file mode 100644 index 173565a1..00000000 --- a/plugins/modules/network/netvisor/pn_vrouterif.py +++ /dev/null @@ -1,490 +0,0 @@ -#!/usr/bin/python -""" PN-CLI vrouter-interface-add/remove/modify """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vrouterif -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to add/remove/modify vrouter-interface. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-interface-add, vrouter-interface-remove, - vrouter-interface-modify command. - - You configure interfaces to vRouter services on a fabric, cluster, - standalone switch or virtual network(VNET). -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch to run the cli on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to add vrouter interface, - 'absent' to remove vrouter interface and 'update' to modify vrouter - interface. - required: True - choices: ['present', 'absent', 'update'] - pn_vrouter_name: - description: - - Specify the name of the vRouter interface. - required: True - pn_vlan: - description: - - Specify the VLAN identifier. This is a value between 1 and 4092. - pn_interface_ip: - description: - - Specify the IP address of the interface in x.x.x.x/n format. - pn_assignment: - description: - - Specify the DHCP method for IP address assignment. - choices: ['none', 'dhcp', 'dhcpv6', 'autov6'] - pn_vxlan: - description: - - Specify the VXLAN identifier. This is a value between 1 and 16777215. - pn_interface: - description: - - Specify if the interface is management, data or span interface. - choices: ['mgmt', 'data', 'span'] - pn_alias: - description: - - Specify an alias for the interface. - pn_exclusive: - description: - - Specify if the interface is exclusive to the configuration. Exclusive - means that other configurations cannot use the interface. Exclusive is - specified when you configure the interface as span interface and allows - higher throughput through the interface. - type: bool - required: False - pn_nic_enable: - description: - - Specify if the NIC is enabled or not - type: bool - pn_vrrp_id: - description: - - Specify the ID for the VRRP interface. The IDs on both vRouters must be - the same IS number. - pn_vrrp_priority: - description: - - Specify the priority for the VRRP interface. This is a value between - 1 (lowest) and 255 (highest). - pn_vrrp_adv_int: - description: - - Specify a VRRP advertisement interval in milliseconds. The range is - from 30 to 40950 with a default value of 1000. - pn_l3port: - description: - - Specify a Layer 3 port for the interface. - pn_secondary_macs: - description: - - Specify a secondary MAC address for the interface. - pn_nic_str: - description: - - Specify the type of NIC. Used for vrouter-interface remove/modify. -''' - -EXAMPLES = """ -- name: Add vrouter-interface - community.network.pn_vrouterif: - pn_cliusername: admin - pn_clipassword: admin - state: 'present' - pn_vrouter_name: 'ansible-vrouter' - pn_interface_ip: 101.101.101.2/24 - pn_vlan: 101 - -- name: Add VRRP.. - community.network.pn_vrouterif: - pn_cliusername: admin - pn_clipassword: admin - state: 'present' - pn_vrouter_name: 'ansible-vrouter' - pn_interface_ip: 101.101.101.2/24 - pn_vrrp_ip: 101.101.101.1/24 - pn_vrrp_priority: 100 - pn_vlan: 101 - -- name: Remove vrouter-interface - community.network.pn_vrouterif: - pn_cliusername: admin - pn_clipassword: admin - state: 'absent' - pn_vrouter_name: 'ansible-vrouter' - pn_interface_ip: 101.101.101.2/24 -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vrouterif command. - returned: on success - type: list -stderr: - description: The set of error responses from the vrouterif command. - returned: on error - type: str -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# Ansible boiler-plate -from ansible.module_utils.basic import AnsibleModule - -VROUTER_EXISTS = None -INTERFACE_EXISTS = None -NIC_EXISTS = None -VRRP_EXISTS = None - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks if vRouter exists on the target node. - This method also checks for idempotency using the vrouter-interface-show - command. - If the given vRouter exists, return VROUTER_EXISTS as True else False. - - If an interface with the given ip exists on the given vRouter, - return INTERFACE_EXISTS as True else False. This is required for - vrouter-interface-add. - - If nic_str exists on the given vRouter, return NIC_EXISTS as True else - False. This is required for vrouter-interface-remove. - - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VROUTER_EXISTS, INTERFACE_EXISTS, NIC_EXISTS - """ - vrouter_name = module.params['pn_vrouter_name'] - interface_ip = module.params['pn_interface_ip'] - nic_str = module.params['pn_nic_str'] - - # Global flags - global VROUTER_EXISTS, INTERFACE_EXISTS, NIC_EXISTS - - # Check for vRouter - check_vrouter = cli + ' vrouter-show format name no-show-headers ' - check_vrouter = shlex.split(check_vrouter) - out = module.run_command(check_vrouter)[1] - out = out.split() - - if vrouter_name in out: - VROUTER_EXISTS = True - else: - VROUTER_EXISTS = False - - if interface_ip: - # Check for interface and VRRP and fetch nic for VRRP - show = cli + ' vrouter-interface-show vrouter-name %s ' % vrouter_name - show += 'ip %s format ip,nic no-show-headers' % interface_ip - show = shlex.split(show) - out = module.run_command(show)[1] - if out: - INTERFACE_EXISTS = True - else: - INTERFACE_EXISTS = False - - if nic_str: - # Check for nic - show = cli + ' vrouter-interface-show vrouter-name %s ' % vrouter_name - show += ' format nic no-show-headers' - show = shlex.split(show) - out = module.run_command(show)[1] - if nic_str in out: - NIC_EXISTS = True - else: - NIC_EXISTS = False - - -def get_nic(module, cli): - """ - This module checks if VRRP interface can be added. If No, return VRRP_EXISTS - as True. - If Yes, fetch the nic string from the primary interface and return nic and - VRRP_EXISTS as False. - :param module: - :param cli: - :return: nic, Global Boolean: VRRP_EXISTS - """ - vrouter_name = module.params['pn_vrouter_name'] - interface_ip = module.params['pn_interface_ip'] - - global VRRP_EXISTS - - # Check for interface and VRRP and fetch nic for VRRP - show = cli + ' vrouter-interface-show vrouter-name %s ' % vrouter_name - show += 'ip %s format ip,nic no-show-headers' % interface_ip - show = shlex.split(show) - out = module.run_command(show)[1] - out = out.split() - - if len(out) > 3: - VRRP_EXISTS = True - return None - else: - nic = out[2] - VRRP_EXISTS = False - return nic - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-interface-add' - if state == 'absent': - command = 'vrouter-interface-remove' - if state == 'update': - command = 'vrouter-interface-modify' - return command - - -def main(): - """ This portion is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent', 'update']), - pn_vrouter_name=dict(required=True, type='str'), - pn_vlan=dict(type='int'), - pn_interface_ip=dict(required=True, type='str'), - pn_assignment=dict(type='str', - choices=['none', 'dhcp', 'dhcpv6', 'autov6']), - pn_vxlan=dict(type='int'), - pn_interface=dict(type='str', choices=['mgmt', 'data', 'span']), - pn_alias=dict(type='str'), - pn_exclusive=dict(type='bool'), - pn_nic_enable=dict(type='bool'), - pn_vrrp_id=dict(type='int'), - pn_vrrp_priority=dict(type='int'), - pn_vrrp_adv_int=dict(type='str'), - pn_l3port=dict(type='str'), - pn_secondary_macs=dict(type='str'), - pn_nic_str=dict(type='str') - ), - required_if=( - ["state", "present", - ["pn_vrouter_name", "pn_interface_ip"]], - ["state", "absent", - ["pn_vrouter_name", "pn_nic_str"]] - ), - ) - - # Accessing the arguments - state = module.params['state'] - vrouter_name = module.params['pn_vrouter_name'] - vlan = module.params['pn_vlan'] - interface_ip = module.params['pn_interface_ip'] - assignment = module.params['pn_assignment'] - vxlan = module.params['pn_vxlan'] - interface = module.params['pn_interface'] - alias = module.params['pn_alias'] - exclusive = module.params['pn_exclusive'] - nic_enable = module.params['pn_nic_enable'] - vrrp_id = module.params['pn_vrrp_id'] - vrrp_priority = module.params['pn_vrrp_priority'] - vrrp_adv_int = module.params['pn_vrrp_adv_int'] - l3port = module.params['pn_l3port'] - secondary_macs = module.params['pn_secondary_macs'] - nic_str = module.params['pn_nic_str'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - check_cli(module, cli) - if command == 'vrouter-interface-add': - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - - if vrrp_id: - vrrp_primary = get_nic(module, cli) - if VRRP_EXISTS is True: - module.exit_json( - skipped=True, - msg=('VRRP interface on %s already exists. Check ' - 'the IP addresses' % vrouter_name) - ) - cli += ' %s vrouter-name %s ' % (command, vrouter_name) - cli += (' ip %s vrrp-primary %s vrrp-id %s ' - % (interface_ip, vrrp_primary, str(vrrp_id))) - if vrrp_priority: - cli += ' vrrp-priority %s ' % str(vrrp_priority) - if vrrp_adv_int: - cli += ' vrrp-adv-int %s ' % vrrp_adv_int - - else: - if INTERFACE_EXISTS is True: - module.exit_json( - skipped=True, - msg=('vRouter interface on %s already exists. Check the ' - 'IP addresses' % vrouter_name) - ) - cli += ' %s vrouter-name %s ' % (command, vrouter_name) - cli += ' ip %s ' % interface_ip - - if vlan: - cli += ' vlan ' + str(vlan) - - if l3port: - cli += ' l3-port ' + l3port - - if assignment: - cli += ' assignment ' + assignment - - if vxlan: - cli += ' vxlan ' + str(vxlan) - - if interface: - cli += ' if ' + interface - - if alias: - cli += ' alias-on ' + alias - - if exclusive is True: - cli += ' exclusive ' - if exclusive is False: - cli += ' no-exclusive ' - - if nic_enable is True: - cli += ' nic-enable ' - if nic_enable is False: - cli += ' nic-disable ' - - if secondary_macs: - cli += ' secondary-macs ' + secondary_macs - - if command == 'vrouter-interface-remove': - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if NIC_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter interface with nic %s does not exist' % nic_str - ) - cli += ' %s vrouter-name %s nic %s ' % (command, vrouter_name, nic_str) - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/netvisor/pn_vrouterlbif.py b/plugins/modules/network/netvisor/pn_vrouterlbif.py deleted file mode 100644 index 379f3142..00000000 --- a/plugins/modules/network/netvisor/pn_vrouterlbif.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/python -""" PN CLI vrouter-loopback-interface-add/remove """ - -# -# 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 . -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: pn_vrouterlbif -author: "Pluribus Networks (@amitsi)" -short_description: CLI command to add/remove vrouter-loopback-interface. -deprecated: - removed_in: 2.0.0 # was Ansible 2.12 - why: Doesn't support latest Pluribus Networks netvisor - alternative: Latest modules will be pushed in Ansible future versions. -description: - - Execute vrouter-loopback-interface-add, vrouter-loopback-interface-remove - commands. - - Each fabric, cluster, standalone switch, or virtual network (VNET) can - provide its tenants with a virtual router (vRouter) service that forwards - traffic between networks and implements Layer 3 protocols. -options: - pn_cliusername: - description: - - Provide login username if user is not root. - required: False - pn_clipassword: - description: - - Provide login password if user is not root. - required: False - pn_cliswitch: - description: - - Target switch(es) to run the cli on. - required: False - default: 'local' - state: - description: - - State the action to perform. Use 'present' to add vrouter loopback - interface and 'absent' to remove vrouter loopback interface. - required: True - choices: ['present', 'absent'] - pn_vrouter_name: - description: - - Specify the name of the vRouter. - required: True - pn_index: - description: - - Specify the interface index from 1 to 255. - pn_interface_ip: - description: - - Specify the IP address. - required: True -''' - -EXAMPLES = """ -- name: Add vrouter-loopback-interface - community.network.pn_vrouterlbif: - state: 'present' - pn_vrouter_name: 'ansible-vrouter' - pn_interface_ip: '104.104.104.1' - -- name: Remove vrouter-loopback-interface - community.network.pn_vrouterlbif: - state: 'absent' - pn_vrouter_name: 'ansible-vrouter' - pn_interface_ip: '104.104.104.1' -""" - -RETURN = """ -command: - description: The CLI command run on the target node(s). - returned: always - type: str -stdout: - description: The set of responses from the vrouterlb command. - returned: always - type: list -stderr: - description: The set of error responses from the vrouterlb command. - returned: on error - type: list -changed: - description: Indicates whether the CLI caused changes on the target. - returned: always - type: bool -""" - -import shlex - -# Ansible boiler-plate -from ansible.module_utils.basic import AnsibleModule - -VROUTER_EXISTS = None -LB_INTERFACE_EXISTS = None -# Index range -MIN_INDEX = 1 -MAX_INDEX = 255 - - -def pn_cli(module): - """ - This method is to generate the cli portion to launch the Netvisor cli. - It parses the username, password, switch parameters from module. - :param module: The Ansible module to fetch username, password and switch - :return: returns the cli string for further processing - """ - username = module.params['pn_cliusername'] - password = module.params['pn_clipassword'] - cliswitch = module.params['pn_cliswitch'] - - if username and password: - cli = '/usr/bin/cli --quiet --user %s:%s ' % (username, password) - else: - cli = '/usr/bin/cli --quiet ' - - if cliswitch == 'local': - cli += ' switch-local ' - else: - cli += ' switch ' + cliswitch - return cli - - -def check_cli(module, cli): - """ - This method checks if vRouter exists on the target node. - This method also checks for idempotency using the - vrouter-loopback-interface-show command. - If the given vRouter exists, return VROUTER_EXISTS as True else False. - If a loopback interface with the given ip exists on the given vRouter, - return LB_INTERFACE_EXISTS as True else False. - - :param module: The Ansible module to fetch input parameters - :param cli: The CLI string - :return Global Booleans: VROUTER_EXISTS, LB_INTERFACE_EXISTS - """ - vrouter_name = module.params['pn_vrouter_name'] - interface_ip = module.params['pn_interface_ip'] - - # Global flags - global VROUTER_EXISTS, LB_INTERFACE_EXISTS - - # Check for vRouter - check_vrouter = cli + ' vrouter-show format name no-show-headers ' - check_vrouter = shlex.split(check_vrouter) - out = module.run_command(check_vrouter)[1] - out = out.split() - - if vrouter_name in out: - VROUTER_EXISTS = True - else: - VROUTER_EXISTS = False - - # Check for loopback interface - show = (cli + ' vrouter-loopback-interface-show vrouter-name %s format ip ' - 'no-show-headers' % vrouter_name) - show = shlex.split(show) - out = module.run_command(show)[1] - out = out.split() - - if interface_ip in out: - LB_INTERFACE_EXISTS = True - else: - LB_INTERFACE_EXISTS = False - - -def run_cli(module, cli): - """ - This method executes the cli command on the target node(s) and returns the - output. The module then exits based on the output. - :param cli: the complete cli string to be executed on the target node(s). - :param module: The Ansible module to fetch command - """ - cliswitch = module.params['pn_cliswitch'] - state = module.params['state'] - command = get_command_from_state(state) - - cmd = shlex.split(cli) - - # 'out' contains the output - # 'err' contains the error messages - result, out, err = module.run_command(cmd) - - print_cli = cli.split(cliswitch)[1] - - # Response in JSON format - if result != 0: - module.exit_json( - command=print_cli, - stderr=err.strip(), - msg="%s operation failed" % command, - changed=False - ) - - if out: - module.exit_json( - command=print_cli, - stdout=out.strip(), - msg="%s operation completed" % command, - changed=True - ) - - else: - module.exit_json( - command=print_cli, - msg="%s operation completed" % command, - changed=True - ) - - -def get_command_from_state(state): - """ - This method gets appropriate command name for the state specified. It - returns the command name for the specified state. - :param state: The state for which the respective command name is required. - """ - command = None - if state == 'present': - command = 'vrouter-loopback-interface-add' - if state == 'absent': - command = 'vrouter-loopback-interface-remove' - return command - - -def main(): - """ This portion is for arguments parsing """ - module = AnsibleModule( - argument_spec=dict( - pn_cliusername=dict(required=False, type='str'), - pn_clipassword=dict(required=False, type='str', no_log=True), - pn_cliswitch=dict(required=False, type='str', default='local'), - state=dict(required=True, type='str', - choices=['present', 'absent']), - pn_vrouter_name=dict(required=True, type='str'), - pn_interface_ip=dict(type='str'), - pn_index=dict(type='int') - ), - required_if=( - ["state", "present", - ["pn_vrouter_name", "pn_interface_ip"]], - ["state", "absent", - ["pn_vrouter_name", "pn_interface_ip"]] - ) - ) - - # Accessing the arguments - state = module.params['state'] - vrouter_name = module.params['pn_vrouter_name'] - interface_ip = module.params['pn_interface_ip'] - index = module.params['pn_index'] - - command = get_command_from_state(state) - - # Building the CLI command string - cli = pn_cli(module) - - if index: - if not MIN_INDEX <= index <= MAX_INDEX: - module.exit_json( - msg="Index must be between 1 and 255", - changed=False - ) - index = str(index) - - if command == 'vrouter-loopback-interface-remove': - check_cli(module, cli) - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg='vRouter %s does not exist' % vrouter_name - ) - if LB_INTERFACE_EXISTS is False: - module.exit_json( - skipped=True, - msg=('Loopback interface with IP %s does not exist on %s' - % (interface_ip, vrouter_name)) - ) - if not index: - # To remove loopback interface, we need the index. - # If index is not specified, get the Loopback interface index - # using the given interface ip. - get_index = cli - get_index += (' vrouter-loopback-interface-show vrouter-name %s ip ' - '%s ' % (vrouter_name, interface_ip)) - get_index += 'format index no-show-headers' - - get_index = shlex.split(get_index) - out = module.run_command(get_index)[1] - index = out.split()[1] - - cli += ' %s vrouter-name %s index %s' % (command, vrouter_name, index) - - if command == 'vrouter-loopback-interface-add': - check_cli(module, cli) - if VROUTER_EXISTS is False: - module.exit_json( - skipped=True, - msg=('vRouter %s does not exist' % vrouter_name) - ) - if LB_INTERFACE_EXISTS is True: - module.exit_json( - skipped=True, - msg=('Loopback interface with IP %s already exists on %s' - % (interface_ip, vrouter_name)) - ) - cli += (' %s vrouter-name %s ip %s' - % (command, vrouter_name, interface_ip)) - if index: - cli += ' index %s ' % index - - run_cli(module, cli) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/nso/nso_action.py b/plugins/modules/network/nso/nso_action.py new file mode 100644 index 00000000..74ca48e0 --- /dev/null +++ b/plugins/modules/network/nso/nso_action.py @@ -0,0 +1,184 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Cisco and/or its affiliates. +# +# 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 . +# + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: nso_action +extends_documentation_fragment: +- community.network.nso + +short_description: Executes Cisco NSO actions and verifies output. +description: + - This module provides support for executing Cisco NSO actions and then + verifying that the output is as expected. +requirements: + - Cisco NSO version 3.4 or higher. +author: "Claes Nästén (@cnasten)" +options: + path: + description: Path to NSO action. + required: true + input: + description: > + NSO action parameters. + output_required: + description: > + Required output parameters. + output_invalid: + description: > + List of result parameter names that will cause the task to fail if they + are present. + validate_strict: + description: > + If set to true, the task will fail if any output parameters not in + output_required is present in the output. + type: bool + default: false +''' + +EXAMPLES = ''' +- name: Sync NSO device + community.network.nso_action: + url: http://localhost:8080/jsonrpc + username: username + password: password + path: /ncs:devices/device{ce0}/sync-from + input: {} +''' + +RETURN = ''' +output: + description: Action output + returned: success + type: dict + sample: + result: true +''' + +from ansible_collections.community.network.plugins.module_utils.network.nso.nso import connect, verify_version, nso_argument_spec +from ansible_collections.community.network.plugins.module_utils.network.nso.nso import normalize_value +from ansible_collections.community.network.plugins.module_utils.network.nso.nso import ModuleFailException, NsoException +from ansible.module_utils.basic import AnsibleModule + + +class NsoAction(object): + REQUIRED_VERSIONS = [ + (3, 4) + ] + + def __init__(self, check_mode, client, + path, input, + output_required, output_invalid, validate_strict): + self._check_mode = check_mode + self._client = client + self._path = path + self._input = input + self._output_required = output_required + self._output_invalid = output_invalid + self._validate_strict = validate_strict + + def main(self): + schema = self._client.get_schema(path=self._path) + if schema['data']['kind'] != 'action': + raise ModuleFailException('{0} is not an action'.format(self._path)) + + input_schema = [c for c in schema['data']['children'] + if c.get('is_action_input', False)] + + for key, value in self._input.items(): + child = next((c for c in input_schema if c['name'] == key), None) + if child is None: + raise ModuleFailException('no parameter {0}'.format(key)) + + # implement type validation in the future + + if self._check_mode: + return {} + else: + return self._run_and_verify() + + def _run_and_verify(self): + output = self._client.run_action(None, self._path, self._input) + for key, value in self._output_required.items(): + if key not in output: + raise ModuleFailException('{0} not in result'.format(key)) + + n_value = normalize_value(value, output[key], key) + if value != n_value: + msg = '{0} value mismatch. expected {1} got {2}'.format( + key, value, n_value) + raise ModuleFailException(msg) + + for key in self._output_invalid.keys(): + if key in output: + raise ModuleFailException('{0} not allowed in result'.format(key)) + + if self._validate_strict: + for name in output.keys(): + if name not in self._output_required: + raise ModuleFailException('{0} not allowed in result'.format(name)) + + return output + + +def main(): + argument_spec = dict( + path=dict(required=True), + input=dict(required=False, type='dict', default={}), + output_required=dict(required=False, type='dict', default={}), + output_invalid=dict(required=False, type='dict', default={}), + validate_strict=dict(required=False, type='bool', default=False) + ) + argument_spec.update(nso_argument_spec) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + p = module.params + + client = connect(p) + nso_action = NsoAction( + module.check_mode, client, + p['path'], + p['input'], + p['output_required'], + p['output_invalid'], + p['validate_strict']) + try: + verify_version(client, NsoAction.REQUIRED_VERSIONS) + + output = nso_action.main() + client.logout() + module.exit_json(changed=True, output=output) + except NsoException as ex: + client.logout() + module.fail_json(msg=ex.message) + except ModuleFailException as ex: + client.logout() + module.fail_json(msg=ex.message) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/network/panos/panos_admin.py b/plugins/modules/network/panos/panos_admin.py deleted file mode 100644 index cd0e958b..00000000 --- a/plugins/modules/network/panos/panos_admin.py +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_admin -short_description: Add or modify PAN-OS user accounts password. -description: - - PanOS module that allows changes to the user account passwords by doing - API calls to the Firewall using pan-api as the protocol. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - admin_username: - description: - - username for admin user - default: "admin" - admin_password: - description: - - password for admin user - required: true - role: - description: - - role for admin user - commit: - description: - - commit if changed - type: bool - default: 'yes' -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -# Set the password of user admin to "badpassword" -# Doesn't commit the candidate config - - name: Set admin password - community.network.panos_admin: - ip_address: "192.168.1.1" - password: "admin" - admin_username: admin - admin_password: "badpassword" - commit: False -''' - -RETURN = ''' -status: - description: success status - returned: success - type: str - sample: "okey dokey" -''' -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - -_ADMIN_XPATH = "/config/mgt-config/users/entry[@name='%s']" - - -def admin_exists(xapi, admin_username): - xapi.get(_ADMIN_XPATH % admin_username) - e = xapi.element_root.find('.//entry') - return e - - -def admin_set(xapi, module, admin_username, admin_password, role): - if admin_password is not None: - xapi.op(cmd='request password-hash password "%s"' % admin_password, - cmd_xml=True) - r = xapi.element_root - phash = r.find('.//phash').text - if role is not None: - rbval = "yes" - if role != "superuser" and role != 'superreader': - rbval = "" - - ea = admin_exists(xapi, admin_username) - if ea is not None: - # user exists - changed = False - - if role is not None: - rb = ea.find('.//role-based') - if rb is not None: - if rb[0].tag != role: - changed = True - xpath = _ADMIN_XPATH % admin_username - xpath += '/permissions/role-based/%s' % rb[0].tag - xapi.delete(xpath=xpath) - - xpath = _ADMIN_XPATH % admin_username - xpath += '/permissions/role-based' - xapi.set(xpath=xpath, - element='<%s>%s' % (role, rbval, role)) - - if admin_password is not None: - xapi.edit(xpath=_ADMIN_XPATH % admin_username + '/phash', - element='%s' % phash) - changed = True - - return changed - - # setup the non encrypted part of the monitor - exml = [] - - exml.append('%s' % phash) - exml.append('<%s>%s' - '' % (role, rbval, role)) - - exml = ''.join(exml) - # module.fail_json(msg=exml) - - xapi.set(xpath=_ADMIN_XPATH % admin_username, element=exml) - - return True - - -def main(): - argument_spec = dict( - ip_address=dict(), - password=dict(no_log=True), - username=dict(default='admin'), - admin_username=dict(default='admin'), - admin_password=dict(no_log=True), - role=dict(), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - - if not HAS_LIB: - module.fail_json(msg='pan-python required for this module') - - ip_address = module.params["ip_address"] - if not ip_address: - module.fail_json(msg="ip_address should be specified") - password = module.params["password"] - if not password: - module.fail_json(msg="password is required") - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - admin_username = module.params['admin_username'] - if admin_username is None: - module.fail_json(msg="admin_username is required") - admin_password = module.params['admin_password'] - role = module.params['role'] - commit = module.params['commit'] - - changed = admin_set(xapi, module, admin_username, admin_password, role) - - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_admpwd.py b/plugins/modules/network/panos/panos_admpwd.py deleted file mode 100644 index c9c0ea74..00000000 --- a/plugins/modules/network/panos/panos_admpwd.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_admpwd -short_description: change admin password of PAN-OS device using SSH with SSH key -description: - - Change the admin password of PAN-OS via SSH using a SSH key for authentication. - - Useful for AWS instances where the first login should be done via SSH. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - paramiko -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device - required: true - username: - description: - - username for initial authentication - required: false - default: "admin" - key_filename: - description: - - filename of the SSH Key to use for authentication - required: true - newpassword: - description: - - password to configure for admin on the PAN-OS device - required: true -''' - -EXAMPLES = ''' -# Tries for 10 times to set the admin password of 192.168.1.1 to "badpassword" -# via SSH, authenticating using key /tmp/ssh.key -- name: Set admin password - community.network.panos_admpwd: - ip_address: "192.168.1.1" - username: "admin" - key_filename: "/tmp/ssh.key" - newpassword: "badpassword" - register: result - until: result is not failed - retries: 10 - delay: 30 -''' - -RETURN = ''' -status: - description: success status - returned: success - type: str - sample: "Last login: Fri Sep 16 11:09:20 2016 from 10.35.34.56.....Configuration committed successfully" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.compat.paramiko import paramiko -import time -import sys - -_PROMPTBUFF = 4096 - - -def wait_with_timeout(module, shell, prompt, timeout=60): - now = time.time() - result = "" - while True: - if shell.recv_ready(): - result += shell.recv(_PROMPTBUFF) - endresult = result.strip() - if len(endresult) != 0 and endresult[-1] == prompt: - break - - if time.time() - now > timeout: - module.fail_json(msg="Timeout waiting for prompt") - - return result - - -def set_panwfw_password(module, ip_address, key_filename, newpassword, username): - stdout = "" - - ssh = paramiko.SSHClient() - - # add policy to accept all host keys, I haven't found - # a way to retrieve the instance SSH key fingerprint from AWS - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - ssh.connect(ip_address, username=username, key_filename=key_filename) - shell = ssh.invoke_shell() - - # wait for the shell to start - buff = wait_with_timeout(module, shell, ">") - stdout += buff - - # step into config mode - shell.send('configure\n') - # wait for the config prompt - buff = wait_with_timeout(module, shell, "#") - stdout += buff - - if module.check_mode: - # exit and close connection - shell.send('exit\n') - ssh.close() - return False, 'Connection test successful. Password left intact.' - - # set admin password - shell.send('set mgt-config users ' + username + ' password\n') - - # wait for the password prompt - buff = wait_with_timeout(module, shell, ":") - stdout += buff - - # enter password for the first time - shell.send(newpassword + '\n') - - # wait for the password prompt - buff = wait_with_timeout(module, shell, ":") - stdout += buff - - # enter password for the second time - shell.send(newpassword + '\n') - - # wait for the config mode prompt - buff = wait_with_timeout(module, shell, "#") - stdout += buff - - # commit ! - shell.send('commit\n') - - # wait for the prompt - buff = wait_with_timeout(module, shell, "#", 120) - stdout += buff - - if 'success' not in buff: - module.fail_json(msg="Error setting " + username + " password: " + stdout) - - # exit - shell.send('exit\n') - - ssh.close() - - return True, stdout - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - username=dict(default='admin'), - key_filename=dict(required=True), - newpassword=dict(no_log=True, required=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - if paramiko is None: - module.fail_json(msg='paramiko is required for this module') - - ip_address = module.params["ip_address"] - if not ip_address: - module.fail_json(msg="ip_address should be specified") - key_filename = module.params["key_filename"] - if not key_filename: - module.fail_json(msg="key_filename should be specified") - newpassword = module.params["newpassword"] - if not newpassword: - module.fail_json(msg="newpassword is required") - username = module.params['username'] - - try: - changed, stdout = set_panwfw_password(module, ip_address, key_filename, newpassword, username) - module.exit_json(changed=changed, stdout=stdout) - except Exception: - x = sys.exc_info()[1] - module.fail_json(msg=x) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_cert_gen_ssh.py b/plugins/modules/network/panos/panos_cert_gen_ssh.py deleted file mode 100644 index 61326154..00000000 --- a/plugins/modules/network/panos/panos_cert_gen_ssh.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_cert_gen_ssh -short_description: generates a self-signed certificate using SSH protocol with SSH key -description: - - This module generates a self-signed certificate that can be used by GlobalProtect client, SSL connector, or - - otherwise. Root certificate must be preset on the system first. This module depends on paramiko for ssh. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - paramiko -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device being configured. - required: true - key_filename: - description: - - Location of the filename that is used for the auth. Either I(key_filename) or I(password) is required. - required: true - password: - description: - - Password credentials to use for auth. Either I(key_filename) or I(password) is required. - required: true - cert_friendly_name: - description: - - Human friendly certificate name (not CN but just a friendly name). - required: true - cert_cn: - description: - - Certificate CN (common name) embedded in the certificate signature. - required: true - signed_by: - description: - - Undersigning authority (CA) that MUST already be presents on the device. - required: true - rsa_nbits: - description: - - Number of bits used by the RSA algorithm for the certificate generation. - default: "2048" -''' - -EXAMPLES = ''' -# Generates a new self-signed certificate using ssh -- name: Generate self signed certificate - community.network.panos_cert_gen_ssh: - ip_address: "192.168.1.1" - password: "paloalto" - cert_cn: "1.1.1.1" - cert_friendly_name: "test123" - signed_by: "root-ca" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils._text import to_native -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.compat.paramiko import paramiko -import time - -_PROMPTBUFF = 4096 - - -def wait_with_timeout(module, shell, prompt, timeout=60): - now = time.time() - result = "" - while True: - if shell.recv_ready(): - result += shell.recv(_PROMPTBUFF) - endresult = result.strip() - if len(endresult) != 0 and endresult[-1] == prompt: - break - - if time.time() - now > timeout: - module.fail_json(msg="Timeout waiting for prompt") - - return result - - -def generate_cert(module, ip_address, key_filename, password, - cert_cn, cert_friendly_name, signed_by, rsa_nbits): - stdout = "" - - client = paramiko.SSHClient() - - # add policy to accept all host keys, I haven't found - # a way to retrieve the instance SSH key fingerprint from AWS - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - if not key_filename: - client.connect(ip_address, username="admin", password=password) - else: - client.connect(ip_address, username="admin", key_filename=key_filename) - - shell = client.invoke_shell() - # wait for the shell to start - buff = wait_with_timeout(module, shell, ">") - stdout += buff - - # generate self-signed certificate - if isinstance(cert_cn, list): - cert_cn = cert_cn[0] - cmd = 'request certificate generate signed-by {0} certificate-name {1} name {2} algorithm RSA rsa-nbits {3}\n'.format( - signed_by, cert_friendly_name, cert_cn, rsa_nbits) - shell.send(cmd) - - # wait for the shell to complete - buff = wait_with_timeout(module, shell, ">") - stdout += buff - - # exit - shell.send('exit\n') - - if 'Success' not in buff: - module.fail_json(msg="Error generating self signed certificate: " + stdout) - - client.close() - return stdout - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - key_filename=dict(), - password=dict(no_log=True), - cert_cn=dict(required=True), - cert_friendly_name=dict(required=True), - rsa_nbits=dict(default='2048'), - signed_by=dict(required=True) - - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['key_filename', 'password']]) - if paramiko is None: - module.fail_json(msg='paramiko is required for this module') - - ip_address = module.params["ip_address"] - key_filename = module.params["key_filename"] - password = module.params["password"] - cert_cn = module.params["cert_cn"] - cert_friendly_name = module.params["cert_friendly_name"] - signed_by = module.params["signed_by"] - rsa_nbits = module.params["rsa_nbits"] - - try: - stdout = generate_cert(module, - ip_address, - key_filename, - password, - cert_cn, - cert_friendly_name, - signed_by, - rsa_nbits) - except Exception as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=True, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_check.py b/plugins/modules/network/panos/panos_check.py deleted file mode 100644 index 0d007f3c..00000000 --- a/plugins/modules/network/panos/panos_check.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_check -short_description: check if PAN-OS device is ready for configuration -description: - - Check if PAN-OS device is ready for being configured (no pending jobs). - - The check could be done once or multiple times until the device is ready. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - timeout: - description: - - timeout of API calls - required: false - default: 0 - interval: - description: - - time waited between checks - required: false - default: 0 -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -# single check on 192.168.1.1 with credentials admin/admin -- name: Check if ready - community.network.panos_check: - ip_address: "192.168.1.1" - password: "admin" - -# check for 10 times, every 30 seconds, if device 192.168.1.1 -# is ready, using credentials admin/admin -- name: Wait for reboot - community.network.panos_check: - ip_address: "192.168.1.1" - password: "admin" - register: result - until: result is not failed - retries: 10 - delay: 30 -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -import time - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def check_jobs(jobs, module): - job_check = False - for j in jobs: - status = j.find('.//status') - if status is None: - return False - if status.text != 'FIN': - return False - job_check = True - return job_check - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - timeout=dict(default=0, type='int'), - interval=dict(default=0, type='int') - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - timeout = module.params['timeout'] - interval = module.params['interval'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password, - timeout=60 - ) - - checkpnt = time.time() + timeout - while True: - try: - xapi.op(cmd="show jobs all", cmd_xml=True) - except Exception: - pass - else: - jobs = xapi.element_root.findall('.//job') - if check_jobs(jobs, module): - module.exit_json(changed=True, msg="okey dokey") - - if time.time() > checkpnt: - break - - time.sleep(interval) - - module.fail_json(msg="Timeout") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_commit.py b/plugins/modules/network/panos/panos_commit.py deleted file mode 100644 index e049d7e3..00000000 --- a/plugins/modules/network/panos/panos_commit.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2019, Tomi Raittinen -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_commit -short_description: commit firewall's candidate configuration -description: - - PanOS module that will commit firewall's candidate configuration on - - the device. The new configuration will become active immediately. -author: - - Luigi Mori (@jtschichold) - - Ivan Bojer (@ivanbojer) - - Tomi Raittinen (@traittinen) -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device. - required: true - password: - description: - - Password for authentication. If the value is not specified in the - task, the value of environment variable C(ANSIBLE_NET_PASSWORD) - will be used instead. - required: true - username: - description: - - Username for authentication. If the value is not specified in the - task, the value of environment variable C(ANSIBLE_NET_USERNAME) - will be used instead if defined. C(admin) will be used if nothing - above is defined. - default: admin - interval: - description: - - interval for checking commit job - default: 0.5 - timeout: - description: - - timeout for commit job - sync: - description: - - if commit should be synchronous - type: bool - default: 'yes' - description: - description: - - Commit description/comment - type: str - commit_changes_by: - description: - - Commit changes made by specified admin - type: list - commit_vsys: - description: - - Commit changes for specified VSYS - type: list -''' - -EXAMPLES = ''' -- name: Commit candidate config on 192.168.1.1 in sync mode - community.network.panos_commit: - ip_address: "192.168.1.1" - username: "admin" - password: "admin" -''' - -RETURN = ''' -panos_commit: - description: Information about commit job. - returned: always - type: complex - contains: - job_id: - description: Palo Alto job ID for the commit operation. Only returned if commit job is launched on device. - returned: always - type: str - sample: "139" - status_code: - description: Palo Alto API status code. Null if commit is successful. - returned: always - type: str - sample: 19 - status_detail: - description: Palo Alto API detailed status message. - returned: always - type: str - sample: Configuration committed successfully - status_text: - description: Palo Alto API status text. - returned: always - type: str - sample: success -''' - -from ansible.module_utils.basic import AnsibleModule, env_fallback -import xml.etree.ElementTree as etree - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True, type='str'), - password=dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']), default="admin"), - interval=dict(default=0.5), - timeout=dict(), - sync=dict(type='bool', default=True), - description=dict(type='str'), - commit_changes_by=dict(type='list'), - commit_vsys=dict(type='list') - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - if not ip_address: - module.fail_json(msg="ip_address should be specified") - - password = module.params["password"] - if not password: - module.fail_json(msg="password is required") - - username = module.params['username'] - if not username: - module.fail_json(msg="username is required") - - interval = module.params['interval'] - timeout = module.params['timeout'] - sync = module.params['sync'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - cmd = "" - - description = module.params["description"] - if description: - cmd += "" + description + "" - - commit_changes_by = module.params["commit_changes_by"] - commit_vsys = module.params["commit_vsys"] - - if commit_changes_by or commit_vsys: - - cmd += "" - - if commit_changes_by: - cmd += "" - for admin in commit_changes_by: - cmd += "" + admin + "" - cmd += "" - - if commit_vsys: - cmd += "" - for vsys in commit_vsys: - cmd += "" + vsys + "" - cmd += "" - - cmd += "" - - cmd += "" - - xapi.commit( - cmd=cmd, - sync=sync, - interval=interval, - timeout=timeout - ) - - try: - result = xapi.xml_root().encode('utf-8') - root = etree.fromstring(result) - job_id = root.find('./result/job/id').text - except AttributeError: - job_id = None - - panos_commit_details = dict( - status_text=xapi.status, - status_code=xapi.status_code, - status_detail=xapi.status_detail, - job_id=job_id - ) - - if "Commit failed" in xapi.status_detail: - module.fail_json(msg=xapi.status_detail, panos_commit=panos_commit_details) - - if job_id: - module.exit_json(changed=True, msg="Commit successful.", panos_commit=panos_commit_details) - else: - module.exit_json(changed=False, msg="No changes to commit.", panos_commit=panos_commit_details) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_dag.py b/plugins/modules/network/panos/panos_dag.py deleted file mode 100644 index c824d69b..00000000 --- a/plugins/modules/network/panos/panos_dag.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_dag -short_description: create a dynamic address group -description: - - Create a dynamic address group object in the firewall used for policy rules -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - dag_name: - description: - - name of the dynamic address group - required: true - dag_filter: - description: - - dynamic filter user by the dynamic address group - required: true - commit: - description: - - commit if changed - type: bool - default: 'yes' -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Dag - community.network.panos_dag: - ip_address: "192.168.1.1" - password: "admin" - dag_name: "dag-1" - dag_filter: "'aws-tag.aws:cloudformation:logical-id.ServerInstance' and 'instanceState.running'" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - -_ADDRGROUP_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/vsys/entry[@name='vsys1']/address-group/entry[@name='%s']" - - -def addressgroup_exists(xapi, group_name): - xapi.get(_ADDRGROUP_XPATH % group_name) - e = xapi.element_root.find('.//entry') - if e is None: - return False - return True - - -def add_dag(xapi, dag_name, dag_filter): - if addressgroup_exists(xapi, dag_name): - return False - - # setup the non encrypted part of the monitor - exml = [] - - exml.append('') - exml.append('%s' % dag_filter) - exml.append('') - - exml = ''.join(exml) - xapi.set(xpath=_ADDRGROUP_XPATH % dag_name, element=exml) - - return True - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - dag_name=dict(required=True), - dag_filter=dict(required=True), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - dag_name = module.params['dag_name'] - dag_filter = module.params['dag_filter'] - commit = module.params['commit'] - - changed = add_dag(xapi, dag_name, dag_filter) - - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_dag_tags.py b/plugins/modules/network/panos/panos_dag_tags.py deleted file mode 100644 index 5e2d1223..00000000 --- a/plugins/modules/network/panos/panos_dag_tags.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . -# limitations under the License. - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_dag_tags -short_description: Create tags for DAG's on PAN-OS devices. -description: - - Create the ip address to tag associations. Tags will in turn be used to create DAG's -author: "Vinay Venkataraghavan (@vinayvenkat)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama is not supported. -options: - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - description: - description: - - The purpose / objective of the static Address Group - commit: - description: - - commit if changed - default: true - type: bool - devicegroup: - description: > - - Device groups are used for the Panorama interaction with Firewall(s). The group must exists on Panorama. - If device group is not define we assume that we are contacting Firewall. - operation: - description: - - The action to be taken. Supported values are I(add)/I(update)/I(find)/I(delete). - tag_names: - description: - - The list of the tags that will be added or removed from the IP address. - ip_to_register: - description: - - IP that will be registered with the given tag names. -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Create the tags to map IP addresses - community.network.panos_dag_tags: - ip_address: "{{ ip_address }}" - password: "{{ password }}" - ip_to_register: "{{ ip_to_register }}" - tag_names: "{{ tag_names }}" - description: "Tags to allow certain IP's to access various SaaS Applications" - operation: 'add' - tags: "adddagip" - -- name: List the IP address to tag mapping - community.network.panos_dag_tags: - ip_address: "{{ ip_address }}" - password: "{{ password }}" - tag_names: "{{ tag_names }}" - description: "List the IP address to tag mapping" - operation: 'list' - tags: "listdagip" - -- name: Unregister an IP address from a tag mapping - community.network.panos_dag_tags: - ip_address: "{{ ip_address }}" - password: "{{ password }}" - ip_to_register: "{{ ip_to_register }}" - tag_names: "{{ tag_names }}" - description: "Unregister IP address from tag mappings" - operation: 'delete' - tags: "deletedagip" -''' - -RETURN = ''' -# Default return values -''' - -try: - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - - from pan.xapi import PanXapiError - - HAS_LIB = True -except ImportError: - HAS_LIB = False - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def register_ip_to_tag_map(device, ip_addresses, tag): - exc = None - try: - device.userid.register(ip_addresses, tag) - except PanXapiError as exc: - return False, exc - - return True, exc - - -def get_all_address_group_mapping(device): - exc = None - ret = None - try: - ret = device.userid.get_registered_ip() - except PanXapiError as exc: - return False, exc - - return ret, exc - - -def delete_address_from_mapping(device, ip_address, tags): - exc = None - try: - ret = device.userid.unregister(ip_address, tags) - except PanXapiError as exc: - return False, exc - - return True, exc - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - devicegroup=dict(default=None), - description=dict(default=None), - ip_to_register=dict(type='str', required=False), - tag_names=dict(type='list', required=True), - commit=dict(type='bool', default=True), - operation=dict(type='str', required=True) - ) - - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - commit = module.params['commit'] - devicegroup = module.params['devicegroup'] - operation = module.params['operation'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # If Panorama, validate the devicegroup - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - else: - module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) - - result = None - if operation == 'add': - result, exc = register_ip_to_tag_map(device, - ip_addresses=module.params.get('ip_to_register', None), - tag=module.params.get('tag_names', None) - ) - elif operation == 'list': - result, exc = get_all_address_group_mapping(device) - elif operation == 'delete': - result, exc = delete_address_from_mapping(device, - ip_address=module.params.get('ip_to_register', None), - tags=module.params.get('tag_names', []) - ) - else: - module.fail_json(msg="Unsupported option") - - if not result: - module.fail_json(msg=exc.message) - - if commit: - try: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=True, msg=result) - - -if __name__ == "__main__": - main() diff --git a/plugins/modules/network/panos/panos_import.py b/plugins/modules/network/panos/panos_import.py deleted file mode 100644 index af7453e4..00000000 --- a/plugins/modules/network/panos/panos_import.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_import -short_description: import file on PAN-OS devices -description: - - Import file on PAN-OS device -notes: - - API reference documentation can be read from the C(/api/) directory of your appliance - - Certificate validation is enabled by default as of Ansible 2.6. This may break existing playbooks but should be disabled with caution. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python - - requests - - requests_toolbelt -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - category: - description: - - Category of file uploaded. The default is software. - - See API > Import section of the API reference for category options. - default: software - file: - description: - - Location of the file to import into device. - url: - description: - - URL of the file that will be imported to device. - validate_certs: - description: - - If C(no), SSL certificates will not be validated. Disabling certificate validation is not recommended. - default: yes - type: bool -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -# import software image PanOS_vm-6.1.1 on 192.168.1.1 -- name: Import software image into PAN-OS - community.network.panos_import: - ip_address: 192.168.1.1 - username: admin - password: admin - file: /tmp/PanOS_vm-6.1.1 - category: software -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -import os.path -import xml.etree -import tempfile -import shutil -import os - -try: - import pan.xapi - import requests - import requests_toolbelt - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def import_file(xapi, module, ip_address, file_, category): - xapi.keygen() - - params = { - 'type': 'import', - 'category': category, - 'key': xapi.api_key - } - - filename = os.path.basename(file_) - - mef = requests_toolbelt.MultipartEncoder( - fields={ - 'file': (filename, open(file_, 'rb'), 'application/octet-stream') - } - ) - - r = requests.post( - 'https://' + ip_address + '/api/', - verify=module.params['validate_certs'], - params=params, - headers={'Content-Type': mef.content_type}, - data=mef - ) - - # if something goes wrong just raise an exception - r.raise_for_status() - - resp = xml.etree.ElementTree.fromstring(r.content) - - if resp.attrib['status'] == 'error': - module.fail_json(msg=r.content) - - return True, filename - - -def download_file(url): - r = requests.get(url, stream=True) - fo = tempfile.NamedTemporaryFile(prefix='ai', delete=False) - shutil.copyfileobj(r.raw, fo) - fo.close() - - return fo.name - - -def delete_file(path): - os.remove(path) - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - category=dict(default='software'), - file=dict(), - url=dict(), - validate_certs=dict(type='bool', default=True), - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['file', 'url']]) - if not HAS_LIB: - module.fail_json(msg='pan-python, requests, and requests_toolbelt are required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - file_ = module.params['file'] - url = module.params['url'] - - category = module.params['category'] - - # we can get file from URL or local storage - if url is not None: - file_ = download_file(url) - - try: - changed, filename = import_file(xapi, module, ip_address, file_, category) - except Exception as exc: - module.fail_json(msg=to_native(exc)) - - # cleanup and delete file if local - if url is not None: - delete_file(file_) - - module.exit_json(changed=changed, filename=filename, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_interface.py b/plugins/modules/network/panos/panos_interface.py deleted file mode 100644 index 63dc366e..00000000 --- a/plugins/modules/network/panos/panos_interface.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_interface -short_description: configure data-port network interface for DHCP -description: - - Configure data-port (DP) network interface for DHCP. By default DP interfaces are static. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. -options: - if_name: - description: - - Name of the interface to configure. - required: true - zone_name: - description: > - Name of the zone for the interface. If the zone does not exist it is created but if the zone exists and - it is not of the layer3 type the operation will fail. - required: true - create_default_route: - description: - - Whether or not to add default route with router learned via DHCP. - default: "false" - type: bool - commit: - description: - - Commit if changed - default: true - type: bool -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Enable DHCP client on ethernet1/1 in zone public - interface: - password: "admin" - ip_address: "192.168.1.1" - if_name: "ethernet1/1" - zone_name: "public" - create_default_route: "yes" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - import pan.xapi - from pan.xapi import PanXapiError - HAS_LIB = True -except ImportError: - HAS_LIB = False - -_IF_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/network/interface/ethernet/entry[@name='%s']" - -_ZONE_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/vsys/entry/zone/entry" -_ZONE_XPATH_QUERY = _ZONE_XPATH + "[network/layer3/member/text()='%s']" -_ZONE_XPATH_IF = _ZONE_XPATH + "[@name='%s']/network/layer3/member[text()='%s']" -_VR_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/network/virtual-router/entry" - - -def add_dhcp_if(xapi, if_name, zone_name, create_default_route): - if_xml = [ - '', - '', - '', - '%s', - '' - '' - '' - ] - cdr = 'yes' - if not create_default_route: - cdr = 'no' - if_xml = (''.join(if_xml)) % (if_name, cdr) - xapi.edit(xpath=_IF_XPATH % if_name, element=if_xml) - - xapi.set(xpath=_ZONE_XPATH + "[@name='%s']/network/layer3" % zone_name, - element='%s' % if_name) - xapi.set(xpath=_VR_XPATH + "[@name='default']/interface", - element='%s' % if_name) - - return True - - -def if_exists(xapi, if_name): - xpath = _IF_XPATH % if_name - xapi.get(xpath=xpath) - network = xapi.element_root.find('.//layer3') - return (network is not None) - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - if_name=dict(required=True), - zone_name=dict(required=True), - create_default_route=dict(type='bool', default=False), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - if_name = module.params['if_name'] - zone_name = module.params['zone_name'] - create_default_route = module.params['create_default_route'] - commit = module.params['commit'] - - ifexists = if_exists(xapi, if_name) - - if ifexists: - module.exit_json(changed=False, msg="interface exists, not changed") - - try: - changed = add_dhcp_if(xapi, if_name, zone_name, create_default_route) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_lic.py b/plugins/modules/network/panos/panos_lic.py deleted file mode 100644 index 6a40216d..00000000 --- a/plugins/modules/network/panos/panos_lic.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_lic -short_description: apply authcode to a device/instance -description: - - Apply an authcode to a device. - - The authcode should have been previously registered on the Palo Alto Networks support portal. - - The device should have Internet access. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - auth_code: - description: - - authcode to be applied - required: true - force: - description: - - whether to apply authcode even if device is already licensed - required: false - default: "false" - type: bool -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' - - hosts: localhost - connection: local - tasks: - - name: Fetch license - community.network.panos_lic: - ip_address: "192.168.1.1" - password: "paloalto" - auth_code: "IBADCODE" - register: result - - name: Display serialnumber (if already registered) - ansible.builtin.debug: - var: "{{result.serialnumber}}" -''' - -RETURN = ''' -serialnumber: - description: serialnumber of the device in case that it has been already registered - returned: success - type: str - sample: 007200004214 -''' - - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_serial(xapi, module): - xapi.op(cmd="show system info", cmd_xml=True) - r = xapi.element_root - serial = r.find('.//serial') - if serial is None: - module.fail_json(msg="No tag in show system info") - - serial = serial.text - - return serial - - -def apply_authcode(xapi, module, auth_code): - try: - xapi.op(cmd='request license fetch auth-code "%s"' % auth_code, - cmd_xml=True) - except pan.xapi.PanXapiError: - if hasattr(xapi, 'xml_document'): - if 'Successfully' in xapi.xml_document: - return - - if 'Invalid Auth Code' in xapi.xml_document: - module.fail_json(msg="Invalid Auth Code") - - raise - - return - - -def fetch_authcode(xapi, module): - try: - xapi.op(cmd='request license fetch', cmd_xml=True) - except pan.xapi.PanXapiError: - if hasattr(xapi, 'xml_document'): - if 'Successfully' in xapi.xml_document: - return - - if 'Invalid Auth Code' in xapi.xml_document: - module.fail_json(msg="Invalid Auth Code") - - raise - - return - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - auth_code=dict(), - username=dict(default='admin'), - force=dict(type='bool', default=False) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - auth_code = module.params["auth_code"] - force = module.params['force'] - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - if not force: - serialnumber = get_serial(xapi, module) - if serialnumber != 'unknown': - return module.exit_json(changed=False, serialnumber=serialnumber) - if auth_code: - apply_authcode(xapi, module, auth_code) - else: - fetch_authcode(xapi, module) - - module.exit_json(changed=True, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_loadcfg.py b/plugins/modules/network/panos/panos_loadcfg.py deleted file mode 100644 index 6e34e2d8..00000000 --- a/plugins/modules/network/panos/panos_loadcfg.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_loadcfg -short_description: load configuration on PAN-OS device -description: - - Load configuration on PAN-OS device -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - file: - description: - - configuration file to load - commit: - description: - - commit if changed - type: bool - default: 'yes' -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -# Import and load config file from URL - - name: Import configuration - panos_import: - ip_address: "192.168.1.1" - password: "admin" - url: "{{ConfigURL}}" - category: "configuration" - register: result - - name: Load configuration - community.network.panos_loadcfg: - ip_address: "192.168.1.1" - password: "admin" - file: "{{result.filename}}" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def load_cfgfile(xapi, module, ip_address, file_): - # load configuration file - cmd = '%s' %\ - file_ - - xapi.op(cmd=cmd) - - return True - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - file=dict(), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - file_ = module.params['file'] - commit = module.params['commit'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - changed = load_cfgfile(xapi, module, ip_address, file_) - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_match_rule.py b/plugins/modules/network/panos/panos_match_rule.py deleted file mode 100644 index 14d68b65..00000000 --- a/plugins/modules/network/panos/panos_match_rule.py +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . -# limitations under the License. - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_match_rule -short_description: Test for match against a security rule on PAN-OS devices or Panorama management console. -description: - - Security policies allow you to enforce rules and take action, and can be as general or specific as needed. -author: "Robert Hagen (@rnh556)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama NOT is supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device being configured. - required: true - username: - description: - - Username credentials to use for auth unless I(api_key) is set. - default: "admin" - password: - description: - - Password credentials to use for auth unless I(api_key) is set. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - rule_type: - description: - - Type of rule. Valid types are I(security) or I(nat). - required: true - choices: - - security - - nat - source_zone: - description: - - The source zone. - source_ip: - description: - - The source IP address. - required: true - source_port: - description: - - The source port. - source_user: - description: - - The source user or group. - to_interface: - description: - - The inbound interface in a NAT rule. - destination_zone: - description: - - The destination zone. - destination_ip: - description: - - The destination IP address. - destination_port: - description: - - The destination port. - application: - description: - - The application. - protocol: - description: - - The IP protocol number from 1 to 255. - category: - description: - - URL category - vsys_id: - description: - - ID of the VSYS object. - default: "vsys1" - required: true -''' - -EXAMPLES = ''' -- name: Check security rules for Google DNS - community.network.panos_match_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - rule_type: 'security' - source_ip: '10.0.0.0' - destination_ip: '8.8.8.8' - application: 'dns' - destination_port: '53' - protocol: '17' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -- name: Check security rules inbound SSH with user match - community.network.panos_match_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - rule_type: 'security' - source_ip: '0.0.0.0' - source_user: 'mydomain\\jsmith' - destination_ip: '192.168.100.115' - destination_port: '22' - protocol: '6' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -- name: Check NAT rules for source NAT - community.network.panos_match_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - rule_type: 'nat' - source_zone: 'Prod-DMZ' - source_ip: '10.10.118.50' - to_interface: 'ethernet1/2' - destination_zone: 'Internet' - destination_ip: '0.0.0.0' - protocol: '6' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -- name: Check NAT rules for inbound web - community.network.panos_match_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - rule_type: 'nat' - source_zone: 'Internet' - source_ip: '0.0.0.0' - to_interface: 'ethernet1/1' - destination_zone: 'Prod DMZ' - destination_ip: '192.168.118.50' - destination_port: '80' - protocol: '6' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -- name: Check security rules for outbound POP3 in vsys4 - community.network.panos_match_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - vsys_id: 'vsys4' - rule_type: 'security' - source_ip: '10.0.0.0' - destination_ip: '4.3.2.1' - application: 'pop3' - destination_port: '110' - protocol: '6' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - from pan.xapi import PanXapiError - from pan.xapi import PanXapiError - from pandevice import base - from pandevice import policies - from pandevice import panorama - import xmltodict - import json - - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def create_security_test(**kwargs): - security_test = 'test security-policy-match' - - # Add the source IP (required) - if kwargs['source_ip']: - security_test += ' source \"%s\"' % kwargs['source_ip'] - - # Add the source user (optional) - if kwargs['source_user']: - security_test += ' source-user \"%s\"' % kwargs['source_user'] - - # Add the destination IP (required) - if kwargs['destination_ip']: - security_test += ' destination \"%s\"' % kwargs['destination_ip'] - - # Add the application (optional) - if kwargs['application']: - security_test += ' application \"%s\"' % kwargs['application'] - - # Add the destination port (required) - if kwargs['destination_port']: - security_test += ' destination-port \"%s\"' % kwargs['destination_port'] - - # Add the IP protocol number (required) - if kwargs['protocol']: - security_test += ' protocol \"%s\"' % kwargs['protocol'] - - # Add the URL category (optional) - if kwargs['category']: - security_test += ' category \"%s\"' % kwargs['category'] - - # Return the resulting string - return security_test - - -def create_nat_test(**kwargs): - nat_test = 'test nat-policy-match' - - # Add the source zone (optional) - if kwargs['source_zone']: - nat_test += ' from \"%s\"' % kwargs['source_zone'] - - # Add the source IP (required) - if kwargs['source_ip']: - nat_test += ' source \"%s\"' % kwargs['source_ip'] - - # Add the source user (optional) - if kwargs['source_port']: - nat_test += ' source-port \"%s\"' % kwargs['source_port'] - - # Add inbound interface (optional) - if kwargs['to_interface']: - nat_test += ' to-interface \"%s\"' % kwargs['to_interface'] - - # Add the destination zone (optional) - if kwargs['destination_zone']: - nat_test += ' to \"%s\"' % kwargs['destination_zone'] - - # Add the destination IP (required) - if kwargs['destination_ip']: - nat_test += ' destination \"%s\"' % kwargs['destination_ip'] - - # Add the destination port (optional) - if kwargs['destination_port']: - nat_test += ' destination-port \"%s\"' % kwargs['destination_port'] - - # Add the IP protocol number (required) - if kwargs['protocol']: - nat_test += ' protocol \"%s\"' % kwargs['protocol'] - - # Return the resulting string - return nat_test - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - vsys_id=dict(default='vsys1'), - rule_type=dict(required=True, choices=['security', 'nat']), - source_zone=dict(default=None), - source_ip=dict(default=None), - source_user=dict(default=None), - source_port=dict(default=None, type=int), - to_interface=dict(default=None), - destination_zone=dict(default=None), - category=dict(default=None), - application=dict(default=None), - protocol=dict(default=None, type=int), - destination_ip=dict(default=None), - destination_port=dict(default=None, type=int) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']]) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - vsys_id = module.params['vsys_id'] - rule_type = module.params['rule_type'] - source_zone = module.params['source_zone'] - source_ip = module.params['source_ip'] - source_user = module.params['source_user'] - source_port = module.params['source_port'] - to_interface = module.params['to_interface'] - destination_zone = module.params['destination_zone'] - destination_ip = module.params['destination_ip'] - destination_port = module.params['destination_port'] - category = module.params['category'] - application = module.params['application'] - protocol = module.params['protocol'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # Fail the module if this is a Panorama instance - if isinstance(device, panorama.Panorama): - module.fail_json( - failed=1, - msg='Panorama is not supported.' - ) - - # Create and attach security and NAT rulebases. Then populate them. - sec_rule_base = nat_rule_base = policies.Rulebase() - device.add(sec_rule_base) - device.add(nat_rule_base) - policies.SecurityRule.refreshall(sec_rule_base) - policies.NatRule.refreshall(nat_rule_base) - - # Which action shall we take on the object? - if rule_type == 'security': - # Search for the object - test_string = create_security_test( - source_ip=source_ip, - source_user=source_user, - destination_ip=destination_ip, - destination_port=destination_port, - application=application, - protocol=protocol, - category=category - ) - elif rule_type == 'nat': - test_string = create_nat_test( - source_zone=source_zone, - source_ip=source_ip, - source_port=source_port, - to_interface=to_interface, - destination_zone=destination_zone, - destination_ip=destination_ip, - destination_port=destination_port, - protocol=protocol - ) - - # Submit the op command with the appropriate test string - try: - response = device.op(cmd=test_string, vsys=vsys_id) - except PanXapiError as exc: - module.fail_json(msg=exc.message) - - if response.find('result/rules').__len__() == 1: - rule_name = response.find('result/rules/entry').text.split(';')[0] - elif rule_type == 'nat': - module.exit_json(msg='No matching NAT rule.') - else: - module.fail_json(msg='Rule match failed. Please check playbook syntax.') - - if rule_type == 'security': - rule_match = sec_rule_base.find(rule_name, policies.SecurityRule) - elif rule_type == 'nat': - rule_match = nat_rule_base.find(rule_name, policies.NatRule) - - # Print out the rule - module.exit_json( - stdout_lines=json.dumps(xmltodict.parse(rule_match.element_str()), indent=2), - msg='Rule matched' - ) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_mgtconfig.py b/plugins/modules/network/panos/panos_mgtconfig.py deleted file mode 100644 index aedb2dc5..00000000 --- a/plugins/modules/network/panos/panos_mgtconfig.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_mgtconfig -short_description: configure management settings of device -description: - - Configure management settings of device -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - dns_server_primary: - description: - - address of primary DNS server - dns_server_secondary: - description: - - address of secondary DNS server - panorama_primary: - description: - - address of primary Panorama server - panorama_secondary: - description: - - address of secondary Panorama server - commit: - description: - - commit if changed - type: bool - default: 'yes' -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Set dns and panorama - community.network.panos_mgtconfig: - ip_address: "192.168.1.1" - password: "admin" - dns_server_primary: "1.1.1.1" - dns_server_secondary: "1.1.1.2" - panorama_primary: "1.1.1.3" - panorama_secondary: "1.1.1.4" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - import pan.xapi - from pan.xapi import PanXapiError - HAS_LIB = True -except ImportError: - HAS_LIB = False - -_XPATH_DNS_SERVERS = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/deviceconfig/system/dns-setting/servers" -_XPATH_PANORAMA_SERVERS = "/config" +\ - "/devices/entry[@name='localhost.localdomain']" +\ - "/deviceconfig/system" - - -def set_dns_server(xapi, new_dns_server, primary=True): - if primary: - tag = "primary" - else: - tag = "secondary" - xpath = _XPATH_DNS_SERVERS + "/" + tag - - # check the current element value - xapi.get(xpath) - val = xapi.element_root.find(".//" + tag) - if val is not None: - # element exists - val = val.text - if val == new_dns_server: - return False - - element = "<%(tag)s>%(value)s" %\ - dict(tag=tag, value=new_dns_server) - xapi.edit(xpath, element) - - return True - - -def set_panorama_server(xapi, new_panorama_server, primary=True): - if primary: - tag = "panorama-server" - else: - tag = "panorama-server-2" - xpath = _XPATH_PANORAMA_SERVERS + "/" + tag - - # check the current element value - xapi.get(xpath) - val = xapi.element_root.find(".//" + tag) - if val is not None: - # element exists - val = val.text - if val == new_panorama_server: - return False - - element = "<%(tag)s>%(value)s" %\ - dict(tag=tag, value=new_panorama_server) - xapi.edit(xpath, element) - - return True - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - dns_server_primary=dict(), - dns_server_secondary=dict(), - panorama_primary=dict(), - panorama_secondary=dict(), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - dns_server_primary = module.params['dns_server_primary'] - dns_server_secondary = module.params['dns_server_secondary'] - panorama_primary = module.params['panorama_primary'] - panorama_secondary = module.params['panorama_secondary'] - commit = module.params['commit'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - changed = False - try: - if dns_server_primary is not None: - changed |= set_dns_server(xapi, dns_server_primary, primary=True) - if dns_server_secondary is not None: - changed |= set_dns_server(xapi, dns_server_secondary, primary=False) - if panorama_primary is not None: - changed |= set_panorama_server(xapi, panorama_primary, primary=True) - if panorama_secondary is not None: - changed |= set_panorama_server(xapi, panorama_secondary, primary=False) - - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_nat_rule.py b/plugins/modules/network/panos/panos_nat_rule.py deleted file mode 100644 index 23f7ae7a..00000000 --- a/plugins/modules/network/panos/panos_nat_rule.py +++ /dev/null @@ -1,467 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# (c) 2016, techbizdev -# 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: panos_nat_rule -short_description: create a policy NAT rule -description: > - - Create a policy nat rule. Keep in mind that we can either end up configuring source NAT, destination NAT, or - both. Instead of splitting it into two we will make a fair attempt to determine which one the user wants. -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer), Robert Hagen (@rnh556)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama is supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device being configured. - required: true - username: - description: - - Username credentials to use for auth unless I(api_key) is set. - default: "admin" - password: - description: - - Password credentials to use for auth unless I(api_key) is set. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - operation: - description: - - The action to be taken. Supported values are I(add)/I(update)/I(find)/I(delete). - required: true - choices: - - add - - update - - delete - - find - devicegroup: - description: - - If Panorama, the device group to put this rule in. - rule_name: - description: - - name of the SNAT rule - required: true - description: - description: - - The description - source_zone: - description: - - list of source zones - required: true - destination_zone: - description: - - destination zone - required: true - source_ip: - description: - - list of source addresses - default: ["any"] - destination_ip: - description: - - list of destination addresses - default: ["any"] - service: - description: - - service - default: "any" - snat_type: - description: - - type of source translation - choices: - - static-ip - - dynamic-ip-and-port - - dynamic-ip - snat_address_type: - description: - - type of source translation. Supported values are I(translated-address)/I(translated-address). - default: 'interface-address' - choices: - - interface-address - - translated-address - snat_static_address: - description: - - Source NAT translated address. Used with Static-IP translation. - snat_dynamic_address: - description: - - Source NAT translated address. Used with Dynamic-IP and Dynamic-IP-and-Port. - snat_interface: - description: - - snat interface - snat_interface_address: - description: - - snat interface address - snat_bidirectional: - description: - - bidirectional flag - type: bool - default: 'no' - dnat_address: - description: - - dnat translated address - dnat_port: - description: - - dnat translated port - tag_name: - description: - - Tag for the NAT rule. - to_interface: - description: - - Destination interface. - default: 'any' - commit: - description: - - Commit configuration if changed. - type: bool - default: 'yes' -''' - -EXAMPLES = ''' -# Create a source and destination nat rule - - name: Create NAT SSH rule for 10.0.1.101 - community.network.panos_nat_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - rule_name: "Web SSH" - source_zone: ["external"] - destination_zone: "external" - source: ["any"] - destination: ["10.0.0.100"] - service: "service-tcp-221" - snat_type: "dynamic-ip-and-port" - snat_interface: "ethernet1/2" - dnat_address: "10.0.1.101" - dnat_port: "22" -''' - -RETURN = ''' -# Default return values -''' - -# import pydevd -# pydevd.settrace('localhost', port=60374, stdoutToServer=True, stderrToServer=True) -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - import pan.xapi - from pan.xapi import PanXapiError - import pandevice - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - from pandevice import policies - import xmltodict - import json - - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, pandevice.panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def get_rulebase(device, devicegroup): - # Build the rulebase - if isinstance(device, pandevice.firewall.Firewall): - rulebase = pandevice.policies.Rulebase() - device.add(rulebase) - elif isinstance(device, pandevice.panorama.Panorama): - dg = panorama.DeviceGroup(devicegroup) - device.add(dg) - rulebase = policies.PreRulebase() - dg.add(rulebase) - else: - return False - policies.NatRule.refreshall(rulebase) - return rulebase - - -def find_rule(rulebase, rule_name): - # Search for the rule name - rule = rulebase.find(rule_name) - if rule: - return rule - else: - return False - - -def create_nat_rule(**kwargs): - nat_rule = policies.NatRule( - name=kwargs['rule_name'], - description=kwargs['description'], - fromzone=kwargs['source_zone'], - source=kwargs['source_ip'], - tozone=kwargs['destination_zone'], - destination=kwargs['destination_ip'], - service=kwargs['service'], - to_interface=kwargs['to_interface'], - nat_type=kwargs['nat_type'] - ) - - # Source translation: Static IP - if kwargs['snat_type'] in ['static-ip'] and kwargs['snat_static_address']: - nat_rule.source_translation_type = kwargs['snat_type'] - nat_rule.source_translation_static_translated_address = kwargs['snat_static_address'] - # Bi-directional flag set? - if kwargs['snat_bidirectional']: - nat_rule.source_translation_static_bi_directional = kwargs['snat_bidirectional'] - - # Source translation: Dynamic IP and port - elif kwargs['snat_type'] in ['dynamic-ip-and-port']: - nat_rule.source_translation_type = kwargs['snat_type'] - nat_rule.source_translation_address_type = kwargs['snat_address_type'] - # Interface address? - if kwargs['snat_interface']: - nat_rule.source_translation_interface = kwargs['snat_interface'] - # Interface IP? - if kwargs['snat_interface_address']: - nat_rule.source_translation_ip_address = kwargs['snat_interface_address'] - else: - nat_rule.source_translation_translated_addresses = kwargs['snat_dynamic_address'] - - # Source translation: Dynamic IP - elif kwargs['snat_type'] in ['dynamic-ip']: - if kwargs['snat_dynamic_address']: - nat_rule.source_translation_type = kwargs['snat_type'] - nat_rule.source_translation_translated_addresses = kwargs['snat_dynamic_address'] - else: - return False - - # Destination translation - if kwargs['dnat_address']: - nat_rule.destination_translated_address = kwargs['dnat_address'] - if kwargs['dnat_port']: - nat_rule.destination_translated_port = kwargs['dnat_port'] - - # Any tags? - if 'tag_name' in kwargs: - nat_rule.tag = kwargs['tag_name'] - - return nat_rule - - -def add_rule(rulebase, nat_rule): - if rulebase: - rulebase.add(nat_rule) - nat_rule.create() - return True - else: - return False - - -def update_rule(rulebase, nat_rule): - if rulebase: - rulebase.add(nat_rule) - nat_rule.apply() - return True - else: - return False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - username=dict(default='admin'), - password=dict(required=True, no_log=True), - api_key=dict(no_log=True), - operation=dict(required=True, choices=['add', 'update', 'delete', 'find']), - rule_name=dict(required=True), - description=dict(), - tag_name=dict(), - source_zone=dict(type='list'), - source_ip=dict(type='list', default=['any']), - destination_zone=dict(), - destination_ip=dict(type='list', default=['any']), - service=dict(default='any'), - to_interface=dict(default='any'), - snat_type=dict(choices=['static-ip', 'dynamic-ip-and-port', 'dynamic-ip']), - snat_address_type=dict(choices=['interface-address', 'translated-address'], default='interface-address'), - snat_static_address=dict(), - snat_dynamic_address=dict(type='list'), - snat_interface=dict(), - snat_interface_address=dict(), - snat_bidirectional=dict(type='bool', default=False), - dnat_address=dict(), - dnat_port=dict(), - devicegroup=dict(), - commit=dict(type='bool', default=True) - ) - - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']]) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - operation = module.params['operation'] - rule_name = module.params['rule_name'] - description = module.params['description'] - tag_name = module.params['tag_name'] - source_zone = module.params['source_zone'] - source_ip = module.params['source_ip'] - destination_zone = module.params['destination_zone'] - destination_ip = module.params['destination_ip'] - service = module.params['service'] - to_interface = module.params['to_interface'] - nat_type = 'ipv4' - snat_type = module.params['snat_type'] - snat_address_type = module.params['snat_address_type'] - snat_static_address = module.params['snat_static_address'] - snat_dynamic_address = module.params['snat_dynamic_address'] - snat_interface = module.params['snat_interface'] - snat_interface_address = module.params['snat_interface_address'] - snat_bidirectional = module.params['snat_bidirectional'] - dnat_address = module.params['dnat_address'] - dnat_port = module.params['dnat_port'] - devicegroup = module.params['devicegroup'] - - commit = module.params['commit'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # If Panorama, validate the devicegroup - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - else: - module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) - - # Get the rulebase - rulebase = get_rulebase(device, dev_group) - - # Which action shall we take on the object? - if operation == "find": - # Search for the rule - match = find_rule(rulebase, rule_name) - # If found, format and return the result - if match: - match_dict = xmltodict.parse(match.element_str()) - module.exit_json( - stdout_lines=json.dumps(match_dict, indent=2), - msg='Rule matched' - ) - else: - module.fail_json(msg='Rule \'%s\' not found. Is the name correct?' % rule_name) - elif operation == "delete": - # Search for the object - match = find_rule(rulebase, rule_name) - # If found, delete it - if match: - try: - match.delete() - if commit: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=True, msg='Rule \'%s\' successfully deleted.' % rule_name) - else: - module.fail_json(msg='Rule \'%s\' not found. Is the name correct?' % rule_name) - elif operation == "add": - # Look for required parameters - if source_zone and destination_zone and nat_type: - pass - else: - module.fail_json(msg='Missing parameter. Required: source_zone, destination_zone, nat_type') - # Search for the rule. Fail if found. - match = find_rule(rulebase, rule_name) - if match: - module.fail_json(msg='Rule \'%s\' already exists. Use operation: \'update\' to change it.' % rule_name) - else: - try: - new_rule = create_nat_rule( - rule_name=rule_name, - description=description, - tag_name=tag_name, - source_zone=source_zone, - destination_zone=destination_zone, - source_ip=source_ip, - destination_ip=destination_ip, - service=service, - to_interface=to_interface, - nat_type=nat_type, - snat_type=snat_type, - snat_address_type=snat_address_type, - snat_static_address=snat_static_address, - snat_dynamic_address=snat_dynamic_address, - snat_interface=snat_interface, - snat_interface_address=snat_interface_address, - snat_bidirectional=snat_bidirectional, - dnat_address=dnat_address, - dnat_port=dnat_port - ) - changed = add_rule(rulebase, new_rule) - if changed and commit: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Rule \'%s\' successfully added.' % rule_name) - elif operation == 'update': - # Search for the rule. Update if found. - match = find_rule(rulebase, rule_name) - if match: - try: - new_rule = create_nat_rule( - rule_name=rule_name, - description=description, - tag_name=tag_name, - source_zone=source_zone, - destination_zone=destination_zone, - source_ip=source_ip, - destination_ip=destination_ip, - service=service, - to_interface=to_interface, - nat_type=nat_type, - snat_type=snat_type, - snat_address_type=snat_address_type, - snat_static_address=snat_static_address, - snat_dynamic_address=snat_dynamic_address, - snat_interface=snat_interface, - snat_interface_address=snat_interface_address, - snat_bidirectional=snat_bidirectional, - dnat_address=dnat_address, - dnat_port=dnat_port - ) - changed = update_rule(rulebase, new_rule) - if changed and commit: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Rule \'%s\' successfully updated.' % rule_name) - else: - module.fail_json(msg='Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % rule_name) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_object.py b/plugins/modules/network/panos/panos_object.py deleted file mode 100644 index 9c3628f2..00000000 --- a/plugins/modules/network/panos/panos_object.py +++ /dev/null @@ -1,489 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . -# limitations under the License. - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_object -short_description: create/read/update/delete object in PAN-OS or Panorama -description: - - Policy objects form the match criteria for policy rules and many other functions in PAN-OS. These may include - address object, address groups, service objects, service groups, and tag. -author: "Bob Hagen (@rnh556)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama is supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device or Panorama management console being configured. - required: true - username: - description: - - Username credentials to use for authentication. - default: "admin" - password: - description: - - Password credentials to use for authentication. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - operation: - description: - - The operation to be performed. Supported values are I(add)/I(delete)/I(find). - required: true - choices: - - add - - update - - delete - - find - addressobject: - description: - - The name of the address object. - address: - description: - - The IP address of the host or network in CIDR notation. - address_type: - description: - - The type of address object definition. Valid types are I(ip-netmask) and I(ip-range). - default: 'ip-netmask' - choices: - - ip-netmask - - ip-range - - fqdn - addressgroup: - description: - - A static group of address objects or dynamic address group. - static_value: - description: - - A group of address objects to be used in an addressgroup definition. - dynamic_value: - description: - - The filter match criteria to be used in a dynamic addressgroup definition. - serviceobject: - description: - - The name of the service object. - source_port: - description: - - The source port to be used in a service object definition. - destination_port: - description: - - The destination port to be used in a service object definition. - protocol: - description: - - The IP protocol to be used in a service object definition. Valid values are I(tcp) or I(udp). - choices: - - tcp - - udp - servicegroup: - description: - - A group of service objects. - services: - description: - - The group of service objects used in a servicegroup definition. - description: - description: - - The description of the object. - tag_name: - description: - - The name of an object or rule tag. - color: - description: > - - The color of the tag object. Valid values are I(red, green, blue, yellow, copper, orange, purple, gray, - light green, cyan, light gray, blue gray, lime, black, gold, and brown). - choices: - - red - - green - - blue - - yellow - - copper - - orange - - purple - - gray - - light green - - cyan - - light gray - - blue gray - - lime - - black - - gold - - brown - devicegroup: - description: > - - The name of the Panorama device group. The group must exist on Panorama. If device group is not defined it - is assumed that we are contacting a firewall. -''' - -EXAMPLES = ''' -- name: Search for shared address object - community.network.panos_object: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - operation: 'find' - address: 'DevNet' - -- name: Create an address group in devicegroup using API key - community.network.panos_object: - ip_address: '{{ ip_address }}' - api_key: '{{ api_key }}' - operation: 'add' - addressgroup: 'Prod_DB_Svrs' - static_value: ['prod-db1', 'prod-db2', 'prod-db3'] - description: 'Production DMZ database servers' - tag_name: 'DMZ' - devicegroup: 'DMZ Firewalls' - -- name: Create a global service for TCP 3306 - community.network.panos_object: - ip_address: '{{ ip_address }}' - api_key: '{{ api_key }}' - operation: 'add' - serviceobject: 'mysql-3306' - destination_port: '3306' - protocol: 'tcp' - description: 'MySQL on tcp/3306' - -- name: Create a global tag - community.network.panos_object: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - operation: 'add' - tag_name: 'ProjectX' - color: 'yellow' - description: 'Associated with Project X' - -- name: Delete an address object from a devicegroup using API key - community.network.panos_object: - ip_address: '{{ ip_address }}' - api_key: '{{ api_key }}' - operation: 'delete' - addressobject: 'Win2K test' -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - import pan.xapi - from pan.xapi import PanXapiError - import pandevice - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - import xmltodict - import json - - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, pandevice.panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def find_object(device, dev_group, obj_name, obj_type): - # Get the firewall objects - obj_type.refreshall(device) - if isinstance(device, pandevice.firewall.Firewall): - addr = device.find(obj_name, obj_type) - return addr - elif isinstance(device, pandevice.panorama.Panorama): - addr = device.find(obj_name, obj_type) - if addr is None: - if dev_group: - device.add(dev_group) - obj_type.refreshall(dev_group) - addr = dev_group.find(obj_name, obj_type) - return addr - else: - return False - - -def create_object(**kwargs): - if kwargs['addressobject']: - newobject = objects.AddressObject( - name=kwargs['addressobject'], - value=kwargs['address'], - type=kwargs['address_type'], - description=kwargs['description'], - tag=kwargs['tag_name'] - ) - if newobject.type and newobject.value: - return newobject - else: - return False - elif kwargs['addressgroup']: - newobject = objects.AddressGroup( - name=kwargs['addressgroup'], - static_value=kwargs['static_value'], - dynamic_value=kwargs['dynamic_value'], - description=kwargs['description'], - tag=kwargs['tag_name'] - ) - if newobject.static_value or newobject.dynamic_value: - return newobject - else: - return False - elif kwargs['serviceobject']: - newobject = objects.ServiceObject( - name=kwargs['serviceobject'], - protocol=kwargs['protocol'], - source_port=kwargs['source_port'], - destination_port=kwargs['destination_port'], - tag=kwargs['tag_name'] - ) - if newobject.protocol and newobject.destination_port: - return newobject - else: - return False - elif kwargs['servicegroup']: - newobject = objects.ServiceGroup( - name=kwargs['servicegroup'], - value=kwargs['services'], - tag=kwargs['tag_name'] - ) - if newobject.value: - return newobject - else: - return False - elif kwargs['tag_name']: - newobject = objects.Tag( - name=kwargs['tag_name'], - color=kwargs['color'], - comments=kwargs['description'] - ) - if newobject.name: - return newobject - else: - return False - else: - return False - - -def add_object(device, dev_group, new_object): - if dev_group: - dev_group.add(new_object) - else: - device.add(new_object) - new_object.create() - return True - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - operation=dict(required=True, choices=['add', 'update', 'delete', 'find']), - addressobject=dict(default=None), - addressgroup=dict(default=None), - serviceobject=dict(default=None), - servicegroup=dict(default=None), - address=dict(default=None), - address_type=dict(default='ip-netmask', choices=['ip-netmask', 'ip-range', 'fqdn']), - static_value=dict(type='list', default=None), - dynamic_value=dict(default=None), - protocol=dict(default=None, choices=['tcp', 'udp']), - source_port=dict(default=None), - destination_port=dict(default=None), - services=dict(type='list', default=None), - description=dict(default=None), - tag_name=dict(default=None), - color=dict(default=None, choices=['red', 'green', 'blue', 'yellow', 'copper', 'orange', 'purple', - 'gray', 'light green', 'cyan', 'light gray', 'blue gray', - 'lime', 'black', 'gold', 'brown']), - devicegroup=dict(default=None) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']], - mutually_exclusive=[['addressobject', 'addressgroup', - 'serviceobject', 'servicegroup', - 'tag_name']] - ) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - operation = module.params['operation'] - addressobject = module.params['addressobject'] - addressgroup = module.params['addressgroup'] - serviceobject = module.params['serviceobject'] - servicegroup = module.params['servicegroup'] - address = module.params['address'] - address_type = module.params['address_type'] - static_value = module.params['static_value'] - dynamic_value = module.params['dynamic_value'] - protocol = module.params['protocol'] - source_port = module.params['source_port'] - destination_port = module.params['destination_port'] - services = module.params['services'] - description = module.params['description'] - tag_name = module.params['tag_name'] - color = module.params['color'] - devicegroup = module.params['devicegroup'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # If Panorama, validate the devicegroup - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - else: - module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) - - # What type of object are we talking about? - if addressobject: - obj_name = addressobject - obj_type = objects.AddressObject - elif addressgroup: - obj_name = addressgroup - obj_type = objects.AddressGroup - elif serviceobject: - obj_name = serviceobject - obj_type = objects.ServiceObject - elif servicegroup: - obj_name = servicegroup - obj_type = objects.ServiceGroup - elif tag_name: - obj_name = tag_name - obj_type = objects.Tag - else: - module.fail_json(msg='No object type defined!') - - # Which operation shall we perform on the object? - if operation == "find": - # Search for the object - match = find_object(device, dev_group, obj_name, obj_type) - - # If found, format and return the result - if match: - match_dict = xmltodict.parse(match.element_str()) - module.exit_json( - stdout_lines=json.dumps(match_dict, indent=2), - msg='Object matched' - ) - else: - module.fail_json(msg='Object \'%s\' not found. Is the name correct?' % obj_name) - elif operation == "delete": - # Search for the object - match = find_object(device, dev_group, obj_name, obj_type) - - # If found, delete it - if match: - try: - match.delete() - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=True, msg='Object \'%s\' successfully deleted' % obj_name) - else: - module.fail_json(msg='Object \'%s\' not found. Is the name correct?' % obj_name) - elif operation == "add": - # Search for the object. Fail if found. - match = find_object(device, dev_group, obj_name, obj_type) - if match: - module.fail_json(msg='Object \'%s\' already exists. Use operation: \'update\' to change it.' % obj_name) - else: - try: - new_object = create_object( - addressobject=addressobject, - addressgroup=addressgroup, - serviceobject=serviceobject, - servicegroup=servicegroup, - address=address, - address_type=address_type, - static_value=static_value, - dynamic_value=dynamic_value, - protocol=protocol, - source_port=source_port, - destination_port=destination_port, - services=services, - description=description, - tag_name=tag_name, - color=color - ) - changed = add_object(device, dev_group, new_object) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Object \'%s\' successfully added' % obj_name) - elif operation == "update": - # Search for the object. Update if found. - match = find_object(device, dev_group, obj_name, obj_type) - if match: - try: - new_object = create_object( - addressobject=addressobject, - addressgroup=addressgroup, - serviceobject=serviceobject, - servicegroup=servicegroup, - address=address, - address_type=address_type, - static_value=static_value, - dynamic_value=dynamic_value, - protocol=protocol, - source_port=source_port, - destination_port=destination_port, - services=services, - description=description, - tag_name=tag_name, - color=color - ) - changed = add_object(device, dev_group, new_object) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Object \'%s\' successfully updated.' % obj_name) - else: - module.fail_json(msg='Object \'%s\' does not exist. Use operation: \'add\' to add it.' % obj_name) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_op.py b/plugins/modules/network/panos/panos_op.py deleted file mode 100644 index 0d027962..00000000 --- a/plugins/modules/network/panos/panos_op.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_op -short_description: execute arbitrary OP commands on PANW devices (e.g. show interface all) -description: This module will allow user to pass and execute any supported OP command on the PANW device. -author: "Ivan Bojer (@ivanbojer)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is NOT supported. - - Panorama is NOT supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device or Panorama management console being configured. - required: true - username: - description: - - Username credentials to use for authentication. - required: false - default: "admin" - password: - description: - - Password credentials to use for authentication. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - cmd: - description: - - The OP command to be performed. - required: true -''' - -EXAMPLES = ''' -- name: Show list of all interfaces - community.network.panos_op: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - cmd: 'show interfaces all' - -- name: Show system info - community.network.panos_op: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - cmd: 'show system info' -''' - -RETURN = ''' -stdout: - description: output of the given OP command as JSON formatted string - returned: success - type: str - sample: "{system: {app-release-date: 2017/05/01 15:09:12}}" - -stdout_xml: - description: output of the given OP command as JSON formatted string - returned: success - type: str - sample: "fw2" -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - from pan.xapi import PanXapiError - import pandevice - from pandevice import base - from pandevice import firewall - from pandevice import panorama - import xmltodict - import json - - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - cmd=dict(required=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']]) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - cmd = module.params['cmd'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - changed = False - try: - xml_output = device.op(cmd, xml=True) - changed = True - except PanXapiError as exc: - if 'non NULL value' in exc.message: - # rewrap and call again - cmd_array = cmd.split() - cmd_array_len = len(cmd_array) - cmd_array[cmd_array_len - 1] = '\"' + cmd_array[cmd_array_len - 1] + '\"' - cmd2 = ' '.join(cmd_array) - try: - xml_output = device.op(cmd2, xml=True) - changed = True - except PanXapiError as exc: - module.fail_json(msg=exc.message) - - obj_dict = xmltodict.parse(xml_output) - json_output = json.dumps(obj_dict) - - module.exit_json(changed=changed, msg="Done", stdout=json_output, stdout_xml=xml_output) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_pg.py b/plugins/modules/network/panos/panos_pg.py deleted file mode 100644 index c8397e9b..00000000 --- a/plugins/modules/network/panos/panos_pg.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_pg -short_description: create a security profiles group -description: - - Create a security profile group -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - pg_name: - description: - - name of the security profile group - required: true - data_filtering: - description: - - name of the data filtering profile - file_blocking: - description: - - name of the file blocking profile - spyware: - description: - - name of the spyware profile - url_filtering: - description: - - name of the url filtering profile - virus: - description: - - name of the anti-virus profile - vulnerability: - description: - - name of the vulnerability profile - wildfire: - description: - - name of the wildfire analysis profile - commit: - description: - - commit if changed - type: bool - default: 'yes' -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Setup security profile group - community.network.panos_pg: - ip_address: "192.168.1.1" - password: "admin" - username: "admin" - pg_name: "pg-default" - virus: "default" - spyware: "default" - vulnerability: "default" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - - -try: - import pan.xapi - from pan.xapi import PanXapiError - HAS_LIB = True -except ImportError: - HAS_LIB = False - -_PG_XPATH = "/config/devices/entry[@name='localhost.localdomain']" +\ - "/vsys/entry[@name='vsys1']" +\ - "/profile-group/entry[@name='%s']" - - -def pg_exists(xapi, pg_name): - xapi.get(_PG_XPATH % pg_name) - e = xapi.element_root.find('.//entry') - if e is None: - return False - return True - - -def add_pg(xapi, pg_name, data_filtering, file_blocking, spyware, - url_filtering, virus, vulnerability, wildfire): - if pg_exists(xapi, pg_name): - return False - - exml = [] - - if data_filtering is not None: - exml.append('%s' % - data_filtering) - if file_blocking is not None: - exml.append('%s' % - file_blocking) - if spyware is not None: - exml.append('%s' % - spyware) - if url_filtering is not None: - exml.append('%s' % - url_filtering) - if virus is not None: - exml.append('%s' % - virus) - if vulnerability is not None: - exml.append('%s' % - vulnerability) - if wildfire is not None: - exml.append('%s' % - wildfire) - - exml = ''.join(exml) - xapi.set(xpath=_PG_XPATH % pg_name, element=exml) - - return True - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - pg_name=dict(required=True), - data_filtering=dict(), - file_blocking=dict(), - spyware=dict(), - url_filtering=dict(), - virus=dict(), - vulnerability=dict(), - wildfire=dict(), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - pg_name = module.params['pg_name'] - data_filtering = module.params['data_filtering'] - file_blocking = module.params['file_blocking'] - spyware = module.params['spyware'] - url_filtering = module.params['url_filtering'] - virus = module.params['virus'] - vulnerability = module.params['vulnerability'] - wildfire = module.params['wildfire'] - commit = module.params['commit'] - - try: - changed = add_pg(xapi, pg_name, data_filtering, file_blocking, - spyware, url_filtering, virus, vulnerability, wildfire) - - if changed and commit: - xapi.commit(cmd="", sync=True, interval=1) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=changed, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_query_rules.py b/plugins/modules/network/panos/panos_query_rules.py deleted file mode 100644 index e7ebd769..00000000 --- a/plugins/modules/network/panos/panos_query_rules.py +++ /dev/null @@ -1,494 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . -# limitations under the License. - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_query_rules -short_description: PANOS module that allows search for security rules in PANW NGFW devices. -description: > - - Security policies allow you to enforce rules and take action, and can be as general or specific as needed. The - policy rules are compared against the incoming traffic in sequence, and because the first rule that matches the - traffic is applied, the more specific rules must precede the more general ones. -author: "Bob Hagen (@rnh556)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) - - xmltodict can be obtains from PyPI U(https://pypi.org/project/xmltodict/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama is supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS firewall or Panorama management console being queried. - required: true - username: - description: - - Username credentials to use for authentication. - default: "admin" - password: - description: - - Password credentials to use for authentication. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - application: - description: - - Name of the application or application group to be queried. - source_zone: - description: - - Name of the source security zone to be queried. - source_ip: - description: - - The source IP address to be queried. - source_port: - description: - - The source port to be queried. - destination_zone: - description: - - Name of the destination security zone to be queried. - destination_ip: - description: - - The destination IP address to be queried. - destination_port: - description: - - The destination port to be queried. - protocol: - description: - - The protocol used to be queried. Must be either I(tcp) or I(udp). - choices: - - tcp - - udp - tag_name: - description: - - Name of the rule tag to be queried. - devicegroup: - description: - - The Panorama device group in which to conduct the query. -''' - -EXAMPLES = ''' -- name: Search for rules with tcp/3306 - community.network.panos_query_rules: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - source_zone: 'DevNet' - destination_zone: 'DevVPC' - destination_port: '3306' - protocol: 'tcp' - -- name: Search devicegroup for inbound rules to dmz host - community.network.panos_query_rules: - ip_address: '{{ ip_address }}' - api_key: '{{ api_key }}' - destination_zone: 'DMZ' - destination_ip: '10.100.42.18' - address: 'DeviceGroupA' - -- name: Search for rules containing a specified rule tag - community.network.panos_query_rules: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - tag_name: 'ProjectX' -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - from pan.xapi import PanXapiError - import pandevice - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - from pandevice import policies - import ipaddress - import xmltodict - import json - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, pandevice.panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def get_rulebase(device, devicegroup): - # Build the rulebase - if isinstance(device, firewall.Firewall): - rulebase = policies.Rulebase() - device.add(rulebase) - elif isinstance(device, panorama.Panorama): - dg = panorama.DeviceGroup(devicegroup) - device.add(dg) - rulebase = policies.PreRulebase() - dg.add(rulebase) - else: - return False - policies.SecurityRule.refreshall(rulebase) - return rulebase - - -def get_object(device, dev_group, obj_name): - # Search global address objects - match = device.find(obj_name, objects.AddressObject) - if match: - return match - - # Search global address groups - match = device.find(obj_name, objects.AddressGroup) - if match: - return match - - # Search Panorama device group - if isinstance(device, pandevice.panorama.Panorama): - # Search device group address objects - match = dev_group.find(obj_name, objects.AddressObject) - if match: - return match - - # Search device group address groups - match = dev_group.find(obj_name, objects.AddressGroup) - if match: - return match - return False - - -def addr_in_obj(addr, obj): - ip = ipaddress.ip_address(addr) - # Process address objects - if isinstance(obj, objects.AddressObject): - if obj.type == 'ip-netmask': - net = ipaddress.ip_network(obj.value) - if ip in net: - return True - if obj.type == 'ip-range': - ip_range = obj.value.split('-') - lower = ipaddress.ip_address(ip_range[0]) - upper = ipaddress.ip_address(ip_range[1]) - if lower < ip < upper: - return True - return False - - -def get_services(device, dev_group, svc_list, obj_list): - for svc in svc_list: - - # Search global address objects - global_obj_match = device.find(svc, objects.ServiceObject) - if global_obj_match: - obj_list.append(global_obj_match) - - # Search global address groups - global_grp_match = device.find(svc, objects.ServiceGroup) - if global_grp_match: - get_services(device, dev_group, global_grp_match.value, obj_list) - - # Search Panorama device group - if isinstance(device, pandevice.panorama.Panorama): - - # Search device group address objects - dg_obj_match = dev_group.find(svc, objects.ServiceObject) - if dg_obj_match: - obj_list.append(dg_obj_match) - - # Search device group address groups - dg_grp_match = dev_group.find(svc, objects.ServiceGroup) - if dg_grp_match: - get_services(device, dev_group, dg_grp_match.value, obj_list) - - return obj_list - - -def port_in_svc(orientation, port, protocol, obj): - # Process address objects - if orientation == 'source': - for x in obj.source_port.split(','): - if '-' in x: - port_range = x.split('-') - lower = int(port_range[0]) - upper = int(port_range[1]) - if (lower <= int(port) <= upper) and (obj.protocol == protocol): - return True - else: - if port == x and obj.protocol == protocol: - return True - elif orientation == 'destination': - for x in obj.destination_port.split(','): - if '-' in x: - port_range = x.split('-') - lower = int(port_range[0]) - upper = int(port_range[1]) - if (lower <= int(port) <= upper) and (obj.protocol == protocol): - return True - else: - if port == x and obj.protocol == protocol: - return True - return False - - -def get_tag(device, dev_group, tag_name): - # Search global address objects - match = device.find(tag_name, objects.Tag) - if match: - return match - # Search Panorama device group - if isinstance(device, panorama.Panorama): - # Search device group address objects - match = dev_group.find(tag_name, objects.Tag) - if match: - return match - return False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - application=dict(default=None), - source_zone=dict(default=None), - destination_zone=dict(default=None), - source_ip=dict(default=None), - destination_ip=dict(default=None), - source_port=dict(default=None), - destination_port=dict(default=None), - protocol=dict(default=None, choices=['tcp', 'udp']), - tag_name=dict(default=None), - devicegroup=dict(default=None) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']] - ) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - application = module.params['application'] - source_zone = module.params['source_zone'] - source_ip = module.params['source_ip'] - source_port = module.params['source_port'] - destination_zone = module.params['destination_zone'] - destination_ip = module.params['destination_ip'] - destination_port = module.params['destination_port'] - protocol = module.params['protocol'] - tag_name = module.params['tag_name'] - devicegroup = module.params['devicegroup'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # Grab the global objects - objects.AddressObject.refreshall(device) - objects.AddressGroup.refreshall(device) - objects.ServiceObject.refreshall(device) - objects.ServiceGroup.refreshall(device) - objects.Tag.refreshall(device) - - # If Panorama, validate the devicegroup and grab the devicegroup objects - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - objects.AddressObject.refreshall(dev_group) - objects.AddressGroup.refreshall(dev_group) - objects.ServiceObject.refreshall(dev_group) - objects.ServiceGroup.refreshall(dev_group) - objects.Tag.refreshall(dev_group) - else: - module.fail_json( - failed=1, - msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup - ) - - # Build the rulebase and produce list - rulebase = get_rulebase(device, dev_group) - rulelist = rulebase.children - hitbase = policies.Rulebase() - loose_match = True - - # Process each rule - for rule in rulelist: - hitlist = [] - - if source_zone: - source_zone_match = False - if loose_match and 'any' in rule.fromzone: - source_zone_match = True - else: - for object_string in rule.fromzone: - if object_string == source_zone: - source_zone_match = True - hitlist.append(source_zone_match) - - if destination_zone: - destination_zone_match = False - if loose_match and 'any' in rule.tozone: - destination_zone_match = True - else: - for object_string in rule.tozone: - if object_string == destination_zone: - destination_zone_match = True - hitlist.append(destination_zone_match) - - if source_ip: - source_ip_match = False - if loose_match and 'any' in rule.source: - source_ip_match = True - else: - for object_string in rule.source: - # Get a valid AddressObject or AddressGroup - obj = get_object(device, dev_group, object_string) - # Otherwise the object_string is not an object and should be handled differently - if obj is False: - if '-' in object_string: - obj = ipaddress.ip_address(source_ip) - source_range = object_string.split('-') - source_lower = ipaddress.ip_address(source_range[0]) - source_upper = ipaddress.ip_address(source_range[1]) - if source_lower <= obj <= source_upper: - source_ip_match = True - else: - if source_ip == object_string: - source_ip_match = True - if isinstance(obj, objects.AddressObject) and addr_in_obj(source_ip, obj): - source_ip_match = True - elif isinstance(obj, objects.AddressGroup) and obj.static_value: - for member_string in obj.static_value: - member = get_object(device, dev_group, member_string) - if addr_in_obj(source_ip, member): - source_ip_match = True - hitlist.append(source_ip_match) - - if destination_ip: - destination_ip_match = False - if loose_match and 'any' in rule.destination: - destination_ip_match = True - else: - for object_string in rule.destination: - # Get a valid AddressObject or AddressGroup - obj = get_object(device, dev_group, object_string) - # Otherwise the object_string is not an object and should be handled differently - if obj is False: - if '-' in object_string: - obj = ipaddress.ip_address(destination_ip) - destination_range = object_string.split('-') - destination_lower = ipaddress.ip_address(destination_range[0]) - destination_upper = ipaddress.ip_address(destination_range[1]) - if destination_lower <= obj <= destination_upper: - destination_ip_match = True - else: - if destination_ip == object_string: - destination_ip_match = True - if isinstance(obj, objects.AddressObject) and addr_in_obj(destination_ip, obj): - destination_ip_match = True - elif isinstance(obj, objects.AddressGroup) and obj.static_value: - for member_string in obj.static_value: - member = get_object(device, dev_group, member_string) - if addr_in_obj(destination_ip, member): - destination_ip_match = True - hitlist.append(destination_ip_match) - - if source_port: - source_port_match = False - orientation = 'source' - if loose_match and (rule.service[0] == 'any'): - source_port_match = True - elif rule.service[0] == 'application-default': - source_port_match = False # Fix this once apps are supported - else: - service_list = [] - service_list = get_services(device, dev_group, rule.service, service_list) - for obj in service_list: - if port_in_svc(orientation, source_port, protocol, obj): - source_port_match = True - break - hitlist.append(source_port_match) - - if destination_port: - destination_port_match = False - orientation = 'destination' - if loose_match and (rule.service[0] == 'any'): - destination_port_match = True - elif rule.service[0] == 'application-default': - destination_port_match = False # Fix this once apps are supported - else: - service_list = [] - service_list = get_services(device, dev_group, rule.service, service_list) - for obj in service_list: - if port_in_svc(orientation, destination_port, protocol, obj): - destination_port_match = True - break - hitlist.append(destination_port_match) - - if tag_name: - tag_match = False - if rule.tag: - for object_string in rule.tag: - obj = get_tag(device, dev_group, object_string) - if obj and (obj.name == tag_name): - tag_match = True - hitlist.append(tag_match) - - # Add to hit rulebase - if False not in hitlist: - hitbase.add(rule) - - # Dump the hit rulebase - if hitbase.children: - output_string = xmltodict.parse(hitbase.element_str()) - module.exit_json( - stdout_lines=json.dumps(output_string, indent=2), - msg='%s of %s rules matched' % (hitbase.children.__len__(), rulebase.children.__len__()) - ) - else: - module.fail_json(msg='No matching rules found.') - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_restart.py b/plugins/modules/network/panos/panos_restart.py deleted file mode 100644 index af2d835b..00000000 --- a/plugins/modules/network/panos/panos_restart.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_restart -short_description: restart a device -description: - - Restart a device -author: "Luigi Mori (@jtschichold), Ivan Bojer (@ivanbojer)" -requirements: - - pan-python -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Restart a device - community.network.panos_restart: - ip_address: "192.168.1.1" - username: "admin" - password: "admin" -''' - -RETURN = ''' -status: - description: success status - returned: success - type: str - sample: "okey dokey" -''' - -import sys -import traceback - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - - -def main(): - argument_spec = dict( - ip_address=dict(), - password=dict(no_log=True), - username=dict(default='admin') - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - - if not HAS_LIB: - module.fail_json(msg='pan-python required for this module') - - ip_address = module.params["ip_address"] - if not ip_address: - module.fail_json(msg="ip_address should be specified") - password = module.params["password"] - if not password: - module.fail_json(msg="password is required") - username = module.params['username'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password - ) - - try: - xapi.op(cmd="") - except Exception as e: - if 'succeeded' in to_native(e): - module.exit_json(changed=True, msg=to_native(e)) - else: - module.fail_json(msg=to_native(e), exception=traceback.format_exc()) - - module.exit_json(changed=True, msg="okey dokey") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_sag.py b/plugins/modules/network/panos/panos_sag.py deleted file mode 100644 index d2a899a2..00000000 --- a/plugins/modules/network/panos/panos_sag.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2016, techbizdev -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_sag -short_description: Create a static address group. -description: - - Create a static address group object in the firewall used for policy rules. -author: "Vinay Venkataraghavan (@vinayvenkat)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) - - xmltodict can be obtained from PyPI U(https://pypi.org/project/xmltodict/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -options: - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - sag_name: - description: - - name of the dynamic address group - required: true - sag_match_filter: - description: - - Static filter user by the address group - type: list - devicegroup: - description: > - - The name of the Panorama device group. The group must exist on Panorama. If device group is not defined - it is assumed that we are contacting a firewall. - description: - description: - - The purpose / objective of the static Address Group - tags: - description: - - Tags to be associated with the address group - commit: - description: - - commit if changed - type: bool - default: 'yes' - operation: - description: - - The operation to perform Supported values are I(add)/I(list)/I(delete). - required: true - choices: - - add - - list - - delete -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' -- name: Sag - community.network.panos_sag: - ip_address: "192.168.1.1" - password: "admin" - sag_name: "sag-1" - static_value: ['test-addresses', ] - description: "A description for the static address group" - tags: ["tags to be associated with the group", ] -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def find_object(device, dev_group, obj_name, obj_type): - # Get the firewall objects - obj_type.refreshall(device) - if isinstance(device, firewall.Firewall): - addr = device.find(obj_name, obj_type) - return addr - elif isinstance(device, panorama.Panorama): - addr = device.find(obj_name, obj_type) - if addr is None: - if dev_group: - device.add(dev_group) - obj_type.refreshall(dev_group) - addr = dev_group.find(obj_name, obj_type) - return addr - else: - return False - - -def create_address_group_object(**kwargs): - """ - Create an Address object - - :param kwargs: key word arguments to instantiate AddressGroup object - @return False or ```objects.AddressObject``` - """ - ad_object = objects.AddressGroup( - name=kwargs['address_gp_name'], - static_value=kwargs['sag_match_filter'], - description=kwargs['description'], - tag=kwargs['tag_name'] - ) - if ad_object.static_value or ad_object.dynamic_value: - return ad_object - else: - return None - - -def add_address_group(device, dev_group, ag_object): - """ - Create a new dynamic address group object on the - PAN FW. - - :param device: Firewall Handle - :param dev_group: Panorama device group - :param ag_object: Address group object - """ - - if dev_group: - dev_group.add(ag_object) - else: - device.add(ag_object) - - exc = None - try: - ag_object.create() - except Exception as exc: - return False, exc - - return True, exc - - -def delete_address_group(device, dev_group, obj_name): - """ - - :param device: - :param dev_group: - :param obj_name: - :return: - """ - static_obj = find_object(device, dev_group, obj_name, objects.AddressGroup) - # If found, delete it - - if static_obj: - try: - static_obj.delete() - except Exception as exc: - return False, exc - return True, None - else: - return False, None - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - sag_match_filter=dict(type='list', required=False), - sag_name=dict(required=True), - commit=dict(type='bool', default=True), - devicegroup=dict(default=None), - description=dict(default=None), - tags=dict(type='list', default=[]), - operation=dict(type='str', required=True, choices=['add', 'list', 'delete']) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']]) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - operation = module.params['operation'] - - ag_object = create_address_group_object(address_gp_name=module.params.get('sag_name', None), - sag_match_filter=module.params.get('sag_match_filter', None), - description=module.params.get('description', None), - tag_name=module.params.get('tags', None) - ) - commit = module.params['commit'] - - devicegroup = module.params['devicegroup'] - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # If Panorama, validate the devicegroup - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - else: - module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) - - if operation == 'add': - result, exc = add_address_group(device, dev_group, ag_object) - - if result and commit: - try: - device.commit(sync=True) - except Exception as exc: - module.fail_json(msg=to_native(exc)) - - elif operation == 'delete': - obj_name = module.params.get('sag_name', None) - result, exc = delete_address_group(device, dev_group, obj_name) - if not result and exc: - module.fail_json(msg=exc.message) - elif not result: - module.fail_json(msg="Specified object not found.") - else: - module.fail_json(changed=False, msg="Unsupported option.") - - module.exit_json(changed=True, msg="Address Group Operation Completed.") - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_security_rule.py b/plugins/modules/network/panos/panos_security_rule.py deleted file mode 100644 index bed0c2bc..00000000 --- a/plugins/modules/network/panos/panos_security_rule.py +++ /dev/null @@ -1,571 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# (c) 2016, techbizdev -# 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: panos_security_rule -short_description: Create security rule policy on PAN-OS devices or Panorama management console. -description: - - Security policies allow you to enforce rules and take action, and can be as general or specific as needed. - The policy rules are compared against the incoming traffic in sequence, and because the first rule that matches the traffic is applied, - the more specific rules must precede the more general ones. -author: "Ivan Bojer (@ivanbojer), Robert Hagen (@rnh556)" -requirements: - - pan-python can be obtained from PyPI U(https://pypi.org/project/pan-python/) - - pandevice can be obtained from PyPI U(https://pypi.org/project/pandevice/) - - xmltodict can be obtained from PyPI U(https://pypi.org/project/xmltodict/) -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -notes: - - Checkmode is not supported. - - Panorama is supported. -options: - ip_address: - description: - - IP address (or hostname) of PAN-OS device being configured. - required: true - username: - description: - - Username credentials to use for auth unless I(api_key) is set. - default: "admin" - password: - description: - - Password credentials to use for auth unless I(api_key) is set. - required: true - api_key: - description: - - API key that can be used instead of I(username)/I(password) credentials. - operation: - description: - - The action to be taken. Supported values are I(add)/I(update)/I(find)/I(delete). - default: 'add' - choices: - - add - - update - - delete - - find - category: - description: - - The category. - type: list - default: ['any'] - rule_name: - description: - - Name of the security rule. - required: true - rule_type: - description: - - Type of security rule (version 6.1 of PanOS and above). - default: "universal" - description: - description: - - Description for the security rule. - tag_name: - description: - - Administrative tags that can be added to the rule. Note, tags must be already defined. - source_zone: - description: - - List of source zones. - default: "any" - destination_zone: - description: - - List of destination zones. - default: "any" - source_ip: - description: - - List of source addresses. - default: "any" - source_user: - description: - - Use users to enforce policy for individual users or a group of users. - default: "any" - hip_profiles: - description: > - - If you are using GlobalProtect with host information profile (HIP) enabled, you can also base the policy - on information collected by GlobalProtect. For example, the user access level can be determined HIP that - notifies the firewall about the user's local configuration. - default: "any" - destination_ip: - description: - - List of destination addresses. - default: "any" - application: - description: - - List of applications. - default: "any" - service: - description: - - List of services. - default: "application-default" - log_start: - description: - - Whether to log at session start. - type: bool - log_end: - description: - - Whether to log at session end. - default: true - type: bool - action: - description: - - Action to apply once rules maches. - default: "allow" - group_profile: - description: > - - Security profile group that is already defined in the system. This property supersedes antivirus, - vulnerability, spyware, url_filtering, file_blocking, data_filtering, and wildfire_analysis properties. - antivirus: - description: - - Name of the already defined antivirus profile. - vulnerability: - description: - - Name of the already defined vulnerability profile. - spyware: - description: - - Name of the already defined spyware profile. - url_filtering: - description: - - Name of the already defined url_filtering profile. - file_blocking: - description: - - Name of the already defined file_blocking profile. - data_filtering: - description: - - Name of the already defined data_filtering profile. - wildfire_analysis: - description: - - Name of the already defined wildfire_analysis profile. - devicegroup: - description: > - - Device groups are used for the Panorama interaction with Firewall(s). The group must exists on Panorama. - If device group is not define we assume that we are contacting Firewall. - commit: - description: - - Commit configuration if changed. - type: bool - default: 'yes' -''' - -EXAMPLES = ''' -- name: Add an SSH inbound rule to devicegroup - community.network.panos_security_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - operation: 'add' - rule_name: 'SSH permit' - description: 'SSH rule test' - tag_name: ['ProjectX'] - source_zone: ['public'] - destination_zone: ['private'] - source_ip: ['any'] - source_user: ['any'] - destination_ip: ['1.1.1.1'] - category: ['any'] - application: ['ssh'] - service: ['application-default'] - hip_profiles: ['any'] - action: 'allow' - devicegroup: 'Cloud Edge' - -- name: Add a rule to allow HTTP multimedia only from CDNs - community.network.panos_security_rule: - ip_address: '10.5.172.91' - username: 'admin' - password: 'paloalto' - operation: 'add' - rule_name: 'HTTP Multimedia' - description: 'Allow HTTP multimedia only to host at 1.1.1.1' - source_zone: ['public'] - destination_zone: ['private'] - source_ip: ['any'] - source_user: ['any'] - destination_ip: ['1.1.1.1'] - category: ['content-delivery-networks'] - application: ['http-video', 'http-audio'] - service: ['service-http', 'service-https'] - hip_profiles: ['any'] - action: 'allow' - -- name: Add a more complex rule that uses security profiles - community.network.panos_security_rule: - ip_address: '{{ ip_address }}' - username: '{{ username }}' - password: '{{ password }}' - operation: 'add' - rule_name: 'Allow HTTP w profile' - log_start: false - log_end: true - action: 'allow' - antivirus: 'default' - vulnerability: 'default' - spyware: 'default' - url_filtering: 'default' - wildfire_analysis: 'default' - -- name: Delete a devicegroup security rule - community.network.panos_security_rule: - ip_address: '{{ ip_address }}' - api_key: '{{ api_key }}' - operation: 'delete' - rule_name: 'Allow telnet' - devicegroup: 'DC Firewalls' - -- name: Find a specific security rule - community.network.panos_security_rule: - ip_address: '{{ ip_address }}' - password: '{{ password }}' - operation: 'find' - rule_name: 'Allow RDP to DCs' - register: result -- ansible.builtin.debug: msg='{{result.stdout_lines}}' - -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - -try: - import pan.xapi - from pan.xapi import PanXapiError - import pandevice - from pandevice import base - from pandevice import firewall - from pandevice import panorama - from pandevice import objects - from pandevice import policies - import xmltodict - import json - - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def get_devicegroup(device, devicegroup): - dg_list = device.refresh_devices() - for group in dg_list: - if isinstance(group, pandevice.panorama.DeviceGroup): - if group.name == devicegroup: - return group - return False - - -def get_rulebase(device, devicegroup): - # Build the rulebase - if isinstance(device, pandevice.firewall.Firewall): - rulebase = pandevice.policies.Rulebase() - device.add(rulebase) - elif isinstance(device, pandevice.panorama.Panorama): - dg = panorama.DeviceGroup(devicegroup) - device.add(dg) - rulebase = policies.PreRulebase() - dg.add(rulebase) - else: - return False - policies.SecurityRule.refreshall(rulebase) - return rulebase - - -def find_rule(rulebase, rule_name): - # Search for the rule name - rule = rulebase.find(rule_name) - if rule: - return rule - else: - return False - - -def rule_is_match(propose_rule, current_rule): - - match_check = ['name', 'description', 'group_profile', 'antivirus', 'vulnerability', - 'spyware', 'url_filtering', 'file_blocking', 'data_filtering', - 'wildfire_analysis', 'type', 'action', 'tag', 'log_start', 'log_end'] - list_check = ['tozone', 'fromzone', 'source', 'source_user', 'destination', 'category', - 'application', 'service', 'hip_profiles'] - - for check in match_check: - propose_check = getattr(propose_rule, check, None) - current_check = getattr(current_rule, check, None) - if propose_check != current_check: - return False - for check in list_check: - propose_check = getattr(propose_rule, check, []) - current_check = getattr(current_rule, check, []) - if set(propose_check) != set(current_check): - return False - return True - - -def create_security_rule(**kwargs): - security_rule = policies.SecurityRule( - name=kwargs['rule_name'], - description=kwargs['description'], - fromzone=kwargs['source_zone'], - source=kwargs['source_ip'], - source_user=kwargs['source_user'], - hip_profiles=kwargs['hip_profiles'], - tozone=kwargs['destination_zone'], - destination=kwargs['destination_ip'], - application=kwargs['application'], - service=kwargs['service'], - category=kwargs['category'], - log_start=kwargs['log_start'], - log_end=kwargs['log_end'], - action=kwargs['action'], - type=kwargs['rule_type'] - ) - - if 'tag_name' in kwargs: - security_rule.tag = kwargs['tag_name'] - - # profile settings - if 'group_profile' in kwargs: - security_rule.group = kwargs['group_profile'] - else: - if 'antivirus' in kwargs: - security_rule.virus = kwargs['antivirus'] - if 'vulnerability' in kwargs: - security_rule.vulnerability = kwargs['vulnerability'] - if 'spyware' in kwargs: - security_rule.spyware = kwargs['spyware'] - if 'url_filtering' in kwargs: - security_rule.url_filtering = kwargs['url_filtering'] - if 'file_blocking' in kwargs: - security_rule.file_blocking = kwargs['file_blocking'] - if 'data_filtering' in kwargs: - security_rule.data_filtering = kwargs['data_filtering'] - if 'wildfire_analysis' in kwargs: - security_rule.wildfire_analysis = kwargs['wildfire_analysis'] - return security_rule - - -def add_rule(rulebase, sec_rule): - if rulebase: - rulebase.add(sec_rule) - sec_rule.create() - return True - else: - return False - - -def update_rule(rulebase, nat_rule): - if rulebase: - rulebase.add(nat_rule) - nat_rule.apply() - return True - else: - return False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(no_log=True), - username=dict(default='admin'), - api_key=dict(no_log=True), - operation=dict(default='add', choices=['add', 'update', 'delete', 'find']), - rule_name=dict(required=True), - description=dict(default=''), - tag_name=dict(type='list'), - destination_zone=dict(type='list', default=['any']), - source_zone=dict(type='list', default=['any']), - source_ip=dict(type='list', default=["any"]), - source_user=dict(type='list', default=['any']), - destination_ip=dict(type='list', default=["any"]), - category=dict(type='list', default=['any']), - application=dict(type='list', default=['any']), - service=dict(type='list', default=['application-default']), - hip_profiles=dict(type='list', default=['any']), - group_profile=dict(), - antivirus=dict(), - vulnerability=dict(), - spyware=dict(), - url_filtering=dict(), - file_blocking=dict(), - data_filtering=dict(), - wildfire_analysis=dict(), - log_start=dict(type='bool', default=False), - log_end=dict(type='bool', default=True), - rule_type=dict(default='universal'), - action=dict(default='allow'), - devicegroup=dict(), - commit=dict(type='bool', default=True) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, - required_one_of=[['api_key', 'password']]) - if not HAS_LIB: - module.fail_json(msg='Missing required libraries.') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - api_key = module.params['api_key'] - operation = module.params['operation'] - rule_name = module.params['rule_name'] - description = module.params['description'] - tag_name = module.params['tag_name'] - source_zone = module.params['source_zone'] - source_ip = module.params['source_ip'] - source_user = module.params['source_user'] - hip_profiles = module.params['hip_profiles'] - destination_zone = module.params['destination_zone'] - destination_ip = module.params['destination_ip'] - application = module.params['application'] - service = module.params['service'] - category = module.params['category'] - log_start = module.params['log_start'] - log_end = module.params['log_end'] - action = module.params['action'] - group_profile = module.params['group_profile'] - antivirus = module.params['antivirus'] - vulnerability = module.params['vulnerability'] - spyware = module.params['spyware'] - url_filtering = module.params['url_filtering'] - file_blocking = module.params['file_blocking'] - data_filtering = module.params['data_filtering'] - wildfire_analysis = module.params['wildfire_analysis'] - rule_type = module.params['rule_type'] - devicegroup = module.params['devicegroup'] - - commit = module.params['commit'] - - # Create the device with the appropriate pandevice type - device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) - - # If Panorama, validate the devicegroup - dev_group = None - if devicegroup and isinstance(device, panorama.Panorama): - dev_group = get_devicegroup(device, devicegroup) - if dev_group: - device.add(dev_group) - else: - module.fail_json(msg='\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) - - # Get the rulebase - rulebase = get_rulebase(device, dev_group) - - # Which action shall we take on the object? - if operation == "find": - # Search for the object - match = find_rule(rulebase, rule_name) - # If found, format and return the result - if match: - match_dict = xmltodict.parse(match.element_str()) - module.exit_json( - stdout_lines=json.dumps(match_dict, indent=2), - msg='Rule matched' - ) - else: - module.fail_json(msg='Rule \'%s\' not found. Is the name correct?' % rule_name) - elif operation == "delete": - # Search for the object - match = find_rule(rulebase, rule_name) - # If found, delete it - if match: - try: - if commit: - match.delete() - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - - module.exit_json(changed=True, msg='Rule \'%s\' successfully deleted' % rule_name) - else: - module.fail_json(msg='Rule \'%s\' not found. Is the name correct?' % rule_name) - elif operation == "add": - new_rule = create_security_rule( - rule_name=rule_name, - description=description, - tag_name=tag_name, - source_zone=source_zone, - destination_zone=destination_zone, - source_ip=source_ip, - source_user=source_user, - destination_ip=destination_ip, - category=category, - application=application, - service=service, - hip_profiles=hip_profiles, - group_profile=group_profile, - antivirus=antivirus, - vulnerability=vulnerability, - spyware=spyware, - url_filtering=url_filtering, - file_blocking=file_blocking, - data_filtering=data_filtering, - wildfire_analysis=wildfire_analysis, - log_start=log_start, - log_end=log_end, - rule_type=rule_type, - action=action - ) - # Search for the rule. Fail if found. - match = find_rule(rulebase, rule_name) - if match: - if rule_is_match(match, new_rule): - module.exit_json(changed=False, msg='Rule \'%s\' is already in place' % rule_name) - else: - module.fail_json(msg='Rule \'%s\' already exists. Use operation: \'update\' to change it.' % rule_name) - else: - try: - changed = add_rule(rulebase, new_rule) - if changed and commit: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Rule \'%s\' successfully added' % rule_name) - elif operation == 'update': - # Search for the rule. Update if found. - match = find_rule(rulebase, rule_name) - if match: - try: - new_rule = create_security_rule( - rule_name=rule_name, - description=description, - tag_name=tag_name, - source_zone=source_zone, - destination_zone=destination_zone, - source_ip=source_ip, - source_user=source_user, - destination_ip=destination_ip, - category=category, - application=application, - service=service, - hip_profiles=hip_profiles, - group_profile=group_profile, - antivirus=antivirus, - vulnerability=vulnerability, - spyware=spyware, - url_filtering=url_filtering, - file_blocking=file_blocking, - data_filtering=data_filtering, - wildfire_analysis=wildfire_analysis, - log_start=log_start, - log_end=log_end, - rule_type=rule_type, - action=action - ) - changed = update_rule(rulebase, new_rule) - if changed and commit: - device.commit(sync=True) - except PanXapiError as exc: - module.fail_json(msg=to_native(exc)) - module.exit_json(changed=changed, msg='Rule \'%s\' successfully updated' % rule_name) - else: - module.fail_json(msg='Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % rule_name) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/panos/panos_set.py b/plugins/modules/network/panos/panos_set.py deleted file mode 100644 index 3491d64f..00000000 --- a/plugins/modules/network/panos/panos_set.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Ansible module to manage PaloAltoNetworks Firewall -# (c) 2018, Jasper Mackenzie -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: panos_set -short_description: Execute arbitrary commands on a PAN-OS device using XPath and element -description: - - Run an arbitrary 'xapi' command taking an XPath (i.e get) or XPath and element (i.e set). - - See https://github.com/kevinsteves/pan-python/blob/master/doc/pan.xapi.rst for details - - Runs a 'set' command by default - - This should support _all_ commands that your PAN-OS device accepts vi it's cli - - cli commands are found as - - Once logged in issue 'debug cli on' - - Enter configuration mode by issuing 'configure' - - Enter your set (or other) command, for example 'set deviceconfig system timezone Australia/Melbourne' - - returns - - > - "Australia/Melbourne - - The 'xpath' is "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system" - - The 'element' is "Australia/Melbourne" -author: "Jasper Mackenzie (@spmp)" -deprecated: - alternative: Use U(https://galaxy.ansible.com/PaloAltoNetworks/paloaltonetworks) instead. - removed_in: 2.0.0 # was Ansible 2.12 - why: Consolidating code base. -requirements: - - pan-python -options: - ip_address: - description: - - IP address or host FQDN of the target PAN-OS NVA - required: true - username: - description: - - User name for a user with admin rights on the PAN-OS NVA - default: admin - password: - description: - - Password for the given 'username' - required: true - command: - description: - - Xapi method name which supports 'xpath' or 'xpath' and 'element' - choices: - - set - - edit - - delete - - get - - show - - override - default: set - xpath: - description: - - The 'xpath' for the commands configurable - required: true - element: - description: - - The 'element' for the 'xpath' if required -extends_documentation_fragment: -- community.network.panos - -''' - -EXAMPLES = ''' - -- name: Set timezone on PA NVA - community.network.panos_set: - ip_address: "192.168.1.1" - username: "my-random-admin" - password: "admin1234" - xpath: "/config/devices/entry/deviceconfig/system" - element: "Australia/Melbourne" - -- name: Commit configuration - panos_commit: - ip_address: "192.168.1.1" - username: "my-random-admin" - password: "admin1234" -''' - -RETURN = ''' -# Default return values -''' - -from ansible.module_utils.basic import AnsibleModule - -try: - import pan.xapi - HAS_LIB = True -except ImportError: - HAS_LIB = False - - -def main(): - argument_spec = dict( - ip_address=dict(required=True), - password=dict(required=True, no_log=True), - username=dict(default='admin'), - command=dict(default='set', choices=['set', 'edit', 'delete', 'get', 'show', 'override']), - xpath=dict(required=True), - element=dict(default=None) - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - if not HAS_LIB: - module.fail_json(msg='pan-python is required for this module') - - ip_address = module.params["ip_address"] - password = module.params["password"] - username = module.params['username'] - xpath = module.params['xpath'] - element = module.params['element'] - xcommand = module.params['command'] - - xapi = pan.xapi.PanXapi( - hostname=ip_address, - api_username=username, - api_password=password, - timeout=60 - ) - - if element is None: - # Issue command with no `element` - try: - getattr(xapi, xcommand)(xpath=xpath) - except Exception as e: - raise Exception("Failed to run '%s' with xpath: '%s' with the following error: %s" % - (xcommand, xpath, e)) - else: - # Issue command with `element` - try: - getattr(xapi, xcommand)(xpath=xpath, element=element) - except Exception as e: - raise Exception("Failed to run '%s' with xpath: '%s' and element '%s' with the following error: %s" % - (xcommand, xpath, element, e)) - - module.exit_json( - status="success" - ) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/routeros/routeros_api.py b/plugins/modules/network/routeros/routeros_api.py deleted file mode 100644 index 1387ceee..00000000 --- a/plugins/modules/network/routeros/routeros_api.py +++ /dev/null @@ -1,481 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2020, Nikolay Dachev -# GNU General Public License v3.0+ https://www.gnu.org/licenses/gpl-3.0.txt - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' ---- -module: routeros_api -version_added: 1.1.0 -author: "Nikolay Dachev (@NikolayDachev)" -short_description: Ansible module for RouterOS API -description: - - Ansible module for RouterOS API with python librouteros. - - This module can add, remove, update, query and execute arbitrary command in routeros via API. -notes: - - I(add), I(remove), I(update), I(cmd) and I(query) are mutually exclusive. - - I(check_mode) is not supported. -requirements: - - librouteros - - Python >= 3.6 (for librouteros) -options: - hostname: - description: - - RouterOS hostname API. - required: true - type: str - username: - description: - - RouterOS login user. - required: true - type: str - password: - description: - - RouterOS user password. - required: true - type: str - ssl: - description: - - If is set TLS will be used for RouterOS API connection. - required: false - type: bool - port: - description: - - RouterOS api port. If ssl is set, port will apply to ssl connection. - - Defaults are C(8728) for the HTTP API, and C(8729) for the HTTPS API. - type: int - path: - description: - - Main path for all other arguments. - - If other arguments are not set, api will return all items in selected path. - - Example C(ip address). Equivalent of RouterOS CLI C(/ip address print). - required: true - type: str - add: - description: - - Will add selected arguments in selected path to RouterOS config. - - Example C(address=1.1.1.1/32 interface=ether1). - - Equivalent in RouterOS CLI C(/ip address add address=1.1.1.1/32 interface=ether1). - type: str - remove: - description: - - Remove config/value from RouterOS by '.id'. - - Example C(*03) will remove config/value with C(id=*03) in selected path. - - Equivalent in RouterOS CLI C(/ip address remove numbers=1). - - Note C(number) in RouterOS CLI is different from C(.id). - type: str - update: - description: - - Update config/value in RouterOS by '.id' in selected path. - - Example C(.id=*03 address=1.1.1.3/32) and path C(ip address) will replace existing ip address with C(.id=*03). - - Equivalent in RouterOS CLI C(/ip address set address=1.1.1.3/32 numbers=1). - - Note C(number) in RouterOS CLI is different from C(.id). - type: str - query: - description: - - Query given path for selected query attributes from RouterOS aip and return '.id'. - - WHERE is key word which extend query. WHERE format is key operator value - with spaces. - - WHERE valid operators are C(==), C(!=), C(>), C(<). - - Example path C(ip address) and query C(.id address) will return only C(.id) and C(address) for all items in C(ip address) path. - - Example path C(ip address) and query C(.id address WHERE address == 1.1.1.3/32). - will return only C(.id) and C(address) for items in C(ip address) path, where address is eq to 1.1.1.3/32. - - Example path C(interface) and query C(mtu name WHERE mut > 1400) will - return only interfaces C(mtu,name) where mtu is bigger than 1400. - - Equivalent in RouterOS CLI C(/interface print where mtu > 1400). - type: str - cmd: - description: - - Execute any/arbitrary command in selected path, after the command we can add C(.id). - - Example path C(system script) and cmd C(run .id=*03) is equivalent in RouterOS CLI C(/system script run number=0). - - Example path C(ip address) and cmd C(print) is equivalent in RouterOS CLI C(/ip address print). - type: str -''' - -EXAMPLES = ''' ---- -- name: Test routeros_api - hosts: localhost - gather_facts: no - vars: - hostname: "ros_api_hostname/ip" - username: "admin" - password: "secret_password" - - path: "ip address" - - nic: "ether2" - ip1: "1.1.1.1/32" - ip2: "2.2.2.2/32" - ip3: "3.3.3.3/32" - - tasks: - - name: Get "{{ path }} print" - community.network.routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - register: print_path - - - name: Dump "{{ path }} print" output - ansible.builtin.debug: - msg: '{{ print_path }}' - - - name: Add ip address "{{ ip1 }}" and "{{ ip2 }}" - community.network.routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - add: "{{ item }}" - loop: - - "address={{ ip1 }} interface={{ nic }}" - - "address={{ ip2 }} interface={{ nic }}" - register: addout - - - name: Dump "Add ip address" output - ".id" for new added items - ansible.builtin.debug: - msg: '{{ addout }}' - - - name: Query for ".id" in "{{ path }} WHERE address == {{ ip2 }}" - community.network.routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - query: ".id address WHERE address == {{ ip2 }}" - register: queryout - - - name: Dump "Query for" output and set fact with ".id" for "{{ ip2 }}" - ansible.builtin.debug: - msg: '{{ queryout }}' - - - ansible.builtin.set_fact: - query_id : "{{ queryout['msg'][0]['.id'] }}" - - - name: Update ".id = {{ query_id }}" taken with custom fact "fquery_id" - routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - update: ".id={{ query_id }} address={{ ip3 }}" - register: updateout - - - name: Dump "Update" output - ansible.builtin.debug: - msg: '{{ updateout }}' - - - name: Remove ips - stage 1 - query ".id" for "{{ ip2 }}" and "{{ ip3 }}" - routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - query: ".id address WHERE address == {{ item }}" - register: id_to_remove - loop: - - "{{ ip2 }}" - - "{{ ip3 }}" - - - name: set fact for ".id" from "Remove ips - stage 1 - query" - ansible.builtin.set_fact: - to_be_remove: "{{ to_be_remove |default([]) + [item['msg'][0]['.id']] }}" - loop: "{{ id_to_remove.results }}" - - - name: Dump "Remove ips - stage 1 - query" output - ansible.builtin.debug: - msg: '{{ to_be_remove }}' - - # Remove "{{ rmips }}" with ".id" by "to_be_remove" from query - - name: Remove ips - stage 2 - remove "{{ ip2 }}" and "{{ ip3 }}" by '.id' - routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "{{ path }}" - remove: "{{ item }}" - register: remove - loop: "{{ to_be_remove }}" - - - name: Dump "Remove ips - stage 2 - remove" output - ansible.builtin.debug: - msg: '{{ remove }}' - - - name: Arbitrary command example "/system identity print" - routeros_api: - hostname: "{{ hostname }}" - password: "{{ password }}" - username: "{{ username }}" - path: "system identity" - cmd: "print" - register: cmdout - - - name: Dump "Arbitrary command example" output - ansible.builtin.debug: - msg: "{{ cmdout }}" -''' - -RETURN = ''' ---- -message: - description: All outputs are in list with dictionary elements returned from RouterOS api. - sample: C([{...},{...}]) - type: list - returned: always -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.basic import missing_required_lib -from ansible.module_utils._text import to_native - -import ssl -import traceback - -LIB_IMP_ERR = None -try: - from librouteros import connect - from librouteros.query import Key - HAS_LIB = True -except Exception as e: - HAS_LIB = False - LIB_IMP_ERR = traceback.format_exc() - - -class ROS_api_module: - def __init__(self): - module_args = (dict( - username=dict(type='str', required=True), - password=dict(type='str', required=True, no_log=True), - hostname=dict(type='str', required=True), - port=dict(type='int'), - ssl=dict(type='bool', default=False), - path=dict(type='str', required=True), - add=dict(type='str'), - remove=dict(type='str'), - update=dict(type='str'), - cmd=dict(type='str'), - query=dict(type='str'))) - - self.module = AnsibleModule(argument_spec=module_args, - supports_check_mode=False, - mutually_exclusive=(('add', 'remove', 'update', - 'cmd', 'query'),),) - - if not HAS_LIB: - self.module.fail_json(msg=missing_required_lib("librouteros"), - exception=LIB_IMP_ERR) - - self.api = self.ros_api_connect(self.module.params['username'], - self.module.params['password'], - self.module.params['hostname'], - self.module.params['port'], - self.module.params['ssl']) - - self.path = self.list_remove_empty(self.module.params['path'].split(' ')) - self.add = self.module.params['add'] - self.remove = self.module.params['remove'] - self.update = self.module.params['update'] - self.arbitrary = self.module.params['cmd'] - - self.where = None - self.query = self.module.params['query'] - if self.query: - if 'WHERE' in self.query: - split = self.query.split('WHERE') - self.query = self.list_remove_empty(split[0].split(' ')) - self.where = self.list_remove_empty(split[1].split(' ')) - else: - self.query = self.list_remove_empty(self.module.params['query'].split(' ')) - - self.result = dict( - message=[]) - - # create api base path - self.api_path = self.api_add_path(self.api, self.path) - - # api call's - if self.add: - self.api_add() - elif self.remove: - self.api_remove() - elif self.update: - self.api_update() - elif self.query: - self.api_query() - elif self.arbitrary: - self.api_arbitrary() - else: - self.api_get_all() - - def list_remove_empty(self, check_list): - while("" in check_list): - check_list.remove("") - return check_list - - def list_to_dic(self, ldict): - dict = {} - for p in ldict: - if '=' not in p: - self.errors("missing '=' after '%s'" % p) - p = p.split('=') - if p[0] == 'id': - self.errors("'%s' must be '.id'" % p[0]) - if p[1]: - dict[p[0]] = p[1] - return dict - - def api_add_path(self, api, path): - api_path = api.path() - for p in path: - api_path = api_path.join(p) - return api_path - - def api_get_all(self): - try: - for i in self.api_path: - self.result['message'].append(i) - self.return_result(False, True) - except Exception as e: - self.errors(e) - - def api_add(self): - param = self.list_to_dic(self.add.split(' ')) - try: - self.result['message'].append("added: .id= %s" - % self.api_path.add(**param)) - self.return_result(True) - except Exception as e: - self.errors(e) - - def api_remove(self): - try: - self.api_path.remove(self.remove) - self.result['message'].append("removed: .id= %s" % self.remove) - self.return_result(True) - except Exception as e: - self.errors(e) - - def api_update(self): - param = self.list_to_dic(self.update.split(' ')) - if '.id' not in param.keys(): - self.errors("missing '.id' for %s" % param) - try: - self.api_path.update(**param) - self.result['message'].append("updated: %s" % param) - self.return_result(True) - except Exception as e: - self.errors(e) - - def api_query(self): - keys = {} - for k in self.query: - if 'id' in k and k != ".id": - self.errors("'%s' must be '.id'" % k) - keys[k] = Key(k) - try: - if self.where: - if len(self.where) < 3: - self.errors("invalid syntax for 'WHERE %s'" - % ' '.join(self.where)) - - where = [] - if self.where[1] == '==': - select = self.api_path.select(*keys).where(keys[self.where[0]] == self.where[2]) - elif self.where[1] == '!=': - select = self.api_path.select(*keys).where(keys[self.where[0]] != self.where[2]) - elif self.where[1] == '>': - select = self.api_path.select(*keys).where(keys[self.where[0]] > self.where[2]) - elif self.where[1] == '<': - select = self.api_path.select(*keys).where(keys[self.where[0]] < self.where[2]) - else: - self.errors("'%s' is not operator for 'where'" - % self.where[1]) - for row in select: - self.result['message'].append(row) - else: - for row in self.api_path.select(*keys): - self.result['message'].append(row) - if len(self.result['message']) < 1: - msg = "no results for '%s 'query' %s" % (' '.join(self.path), - ' '.join(self.query)) - if self.where: - msg = msg + ' WHERE %s' % ' '.join(self.where) - self.result['message'].append(msg) - self.return_result(False) - except Exception as e: - self.errors(e) - - def api_arbitrary(self): - param = {} - self.arbitrary = self.arbitrary.split(' ') - arb_cmd = self.arbitrary[0] - if len(self.arbitrary) > 1: - param = self.list_to_dic(self.arbitrary[1:]) - try: - arbitrary_result = self.api_path(arb_cmd, **param) - for i in arbitrary_result: - self.result['message'].append(i) - self.return_result(False) - except Exception as e: - self.errors(e) - - def return_result(self, ch_status=False, status=True): - if status == "False": - self.module.fail_json(msg=to_native(self.result['message'])) - else: - self.module.exit_json(changed=ch_status, - msg=self.result['message']) - - def errors(self, e): - if e.__class__.__name__ == 'TrapError': - self.result['message'].append("%s" % e) - self.return_result(False, True) - self.result['message'].append("%s" % e) - self.return_result(False, False) - - def ros_api_connect(self, username, password, host, port, use_ssl): - # connect to routeros api - conn_status = {"connection": {"username": username, - "hostname": host, - "port": port, - "ssl": use_ssl, - "status": "Connected"}} - try: - if use_ssl is True: - if not port: - port = 8729 - conn_status["connection"]["port"] = port - ctx = ssl.create_default_context() - ctx.check_hostname = False - ctx.set_ciphers('ADH:@SECLEVEL=0') - api = connect(username=username, - password=password, - host=host, - ssl_wrapper=ctx.wrap_socket, - port=port) - else: - if not port: - port = 8728 - conn_status["connection"]["port"] = port - api = connect(username=username, - password=password, - host=host, - port=port) - except Exception as e: - conn_status["connection"]["status"] = "error: %s" % e - self.module.fail_json(msg=to_native([conn_status])) - return api - - -def main(): - - ROS_api_module() - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/routeros/routeros_command.py b/plugins/modules/network/routeros/routeros_command.py deleted file mode 100644 index 403df21a..00000000 --- a/plugins/modules/network/routeros/routeros_command.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/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: routeros_command -author: "Egor Zaitsev (@heuels)" -short_description: Run commands on remote devices running MikroTik RouterOS -description: - - Sends arbitrary commands to an RouterOS 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. -options: - commands: - description: - - List of commands to send to the remote RouterOS 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. - 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. - 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'] - 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 - 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 -''' - -EXAMPLES = """ -tasks: - - name: Run command on remote devices - community.network.routeros_command: - commands: /system routerboard print - - - name: Run command and check to see if output contains routeros - community.network.routeros_command: - commands: /system resource print - wait_for: result[0] contains MikroTik - - - name: Run multiple commands on remote nodes - community.network.routeros_command: - commands: - - /system routerboard print - - /system identity print - - - name: Run multiple commands and evaluate the output - community.network.routeros_command: - commands: - - /system routerboard print - - /interface ethernet print - wait_for: - - result[0] contains x86 - - result[1] contains ether1 -""" - -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 re -import time - -from ansible_collections.community.network.plugins.module_utils.network.routeros.routeros import run_commands -from ansible_collections.community.network.plugins.module_utils.network.routeros.routeros import routeros_argument_spec -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ComplexList -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import Conditional -from ansible.module_utils.six import string_types - - -def to_lines(stdout): - for item in stdout: - if isinstance(item, string_types): - item = str(item).split('\n') - yield item - - -def main(): - """main entry point for module execution - """ - argument_spec = dict( - commands=dict(type='list', required=True), - - wait_for=dict(type='list'), - match=dict(default='all', choices=['all', 'any']), - - retries=dict(default=10, type='int'), - interval=dict(default=1, type='int') - ) - - argument_spec.update(routeros_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - result = {'changed': False} - - wait_for = module.params['wait_for'] or list() - conditionals = [Conditional(c) for c in wait_for] - - retries = module.params['retries'] - interval = module.params['interval'] - match = module.params['match'] - - while retries > 0: - responses = run_commands(module, module.params['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({ - 'changed': False, - 'stdout': responses, - 'stdout_lines': list(to_lines(responses)) - }) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/routeros/routeros_facts.py b/plugins/modules/network/routeros/routeros_facts.py deleted file mode 100644 index 05d89152..00000000 --- a/plugins/modules/network/routeros/routeros_facts.py +++ /dev/null @@ -1,629 +0,0 @@ -#!/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: routeros_facts -author: "Egor Zaitsev (@heuels)" -short_description: Collect facts from remote devices running MikroTik RouterOS -description: - - Collects a base set of device facts from a remote device that - is running RotuerOS. This module prepends all of the - base network fact keys with C(ansible_net_). The facts - module will always collect a base set of facts from the device - and can enable or disable collection of additional facts. -options: - gather_subset: - description: - - When supplied, this argument will restrict the facts collected - to a given subset. Possible values for this argument include - C(all), C(hardware), C(config), and C(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: '!config' -''' - -EXAMPLES = """ -- name: Collect all facts from the device - community.network.routeros_facts: - gather_subset: all - -- name: Collect only the config and default facts - community.network.routeros_facts: - gather_subset: - - config - -- name: Do not collect hardware facts - community.network.routeros_facts: - gather_subset: - - "!hardware" -""" - -RETURN = """ -ansible_net_gather_subset: - description: The list of fact subsets collected from the device - returned: always - type: list - -# default -ansible_net_model: - description: The model name returned from the device - returned: always - type: str -ansible_net_serialnum: - description: The serial number of the remote device - returned: always - type: str -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_arch: - description: The CPU architecture of the device - returned: always - type: str - version_added: 1.2.0 -ansible_net_uptime: - description: The uptime of the device - returned: always - type: str - version_added: 1.2.0 -ansible_net_cpu_load: - description: Current CPU load - returned: always - type: str - version_added: 1.2.0 - -# hardware -ansible_net_spacefree_mb: - description: The available disk space on the remote device in MiB - returned: when hardware is configured - type: dict -ansible_net_spacetotal_mb: - description: The total disk space on the remote device in MiB - returned: when hardware is configured - type: dict -ansible_net_memfree_mb: - description: The available free memory on the remote device in MiB - returned: when hardware is configured - type: int -ansible_net_memtotal_mb: - description: The total memory on the remote device in MiB - 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 neighbors from the remote device - returned: when interfaces is configured - type: dict - -# routing -ansible_net_bgp_peer: - description: The dict bgp peer - returned: peer information - type: dict - version_added: 1.2.0 -ansible_net_bgp_vpnv4_route: - description: The dict bgp vpnv4 route - returned: vpnv4 route information - type: dict - version_added: 1.2.0 -ansible_net_bgp_instance: - description: The dict bgp instance - returned: bgp instance information - type: dict - version_added: 1.2.0 -ansible_net_route: - description: The dict routes in all routing table - returned: routes information in all routing table - type: dict - version_added: 1.2.0 -ansible_net_ospf_instance: - description: The dict ospf instance - returned: ospf instance information - type: dict - version_added: 1.2.0 -ansible_net_ospf_neighbor: - description: The dict ospf neighbor - returned: ospf neighbor information - type: dict - version_added: 1.2.0 -""" -import re - -from ansible_collections.community.network.plugins.module_utils.network.routeros.routeros import run_commands -from ansible_collections.community.network.plugins.module_utils.network.routeros.routeros import routeros_argument_spec -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import iteritems - - -class FactsBase(object): - - COMMANDS = list() - - def __init__(self, module): - self.module = module - self.facts = dict() - self.responses = None - - def populate(self): - self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False) - - def run(self, cmd): - return run_commands(self.module, commands=cmd, check_rc=False) - - -class Default(FactsBase): - - COMMANDS = [ - '/system identity print without-paging', - '/system resource print without-paging', - '/system routerboard print without-paging' - ] - - def populate(self): - super(Default, self).populate() - data = self.responses[0] - if data: - self.facts['hostname'] = self.parse_hostname(data) - data = self.responses[1] - if data: - self.facts['version'] = self.parse_version(data) - self.facts['arch'] = self.parse_arch(data) - self.facts['uptime'] = self.parse_uptime(data) - self.facts['cpu_load'] = self.parse_cpu_load(data) - data = self.responses[2] - if data: - self.facts['model'] = self.parse_model(data) - self.facts['serialnum'] = self.parse_serialnum(data) - - def parse_hostname(self, data): - match = re.search(r'name:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_version(self, data): - match = re.search(r'version:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_model(self, data): - match = re.search(r'model:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_arch(self, data): - match = re.search(r'architecture-name:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_uptime(self, data): - match = re.search(r'uptime:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_cpu_load(self, data): - match = re.search(r'cpu-load:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - def parse_serialnum(self, data): - match = re.search(r'serial-number:\s(.*)\s*$', data, re.M) - if match: - return match.group(1) - - -class Hardware(FactsBase): - - COMMANDS = [ - '/system resource print without-paging' - ] - - def populate(self): - super(Hardware, self).populate() - data = self.responses[0] - if data: - self.parse_filesystem_info(data) - self.parse_memory_info(data) - - def parse_filesystem_info(self, data): - match = re.search(r'free-hdd-space:\s(.*)([KMG]iB)', data, re.M) - if match: - self.facts['spacefree_mb'] = self.to_megabytes(match) - match = re.search(r'total-hdd-space:\s(.*)([KMG]iB)', data, re.M) - if match: - self.facts['spacetotal_mb'] = self.to_megabytes(match) - - def parse_memory_info(self, data): - match = re.search(r'free-memory:\s(\d+\.?\d*)([KMG]iB)', data, re.M) - if match: - self.facts['memfree_mb'] = self.to_megabytes(match) - match = re.search(r'total-memory:\s(\d+\.?\d*)([KMG]iB)', data, re.M) - if match: - self.facts['memtotal_mb'] = self.to_megabytes(match) - - def to_megabytes(self, data): - if data.group(2) == 'KiB': - return float(data.group(1)) / 1024 - elif data.group(2) == 'MiB': - return float(data.group(1)) - elif data.group(2) == 'GiB': - return float(data.group(1)) * 1024 - else: - return None - - -class Config(FactsBase): - - COMMANDS = ['/export verbose'] - - def populate(self): - super(Config, self).populate() - data = self.responses[0] - if data: - self.facts['config'] = data - - -class Interfaces(FactsBase): - - COMMANDS = [ - '/interface print detail without-paging', - '/ip address print detail without-paging', - '/ipv6 address print detail without-paging', - '/ip neighbor print detail without-paging' - ] - - DETAIL_RE = re.compile(r'([\w\d\-]+)=\"?(\w{3}/\d{2}/\d{4}\s\d{2}:\d{2}:\d{2}|[\w\d\-\.:/]+)') - WRAPPED_LINE_RE = re.compile(r'^\s+(?!\d)') - - def populate(self): - super(Interfaces, self).populate() - - self.facts['interfaces'] = dict() - self.facts['all_ipv4_addresses'] = list() - self.facts['all_ipv6_addresses'] = list() - self.facts['neighbors'] = list() - - data = self.responses[0] - if data: - interfaces = self.parse_interfaces(data) - self.populate_interfaces(interfaces) - - data = self.responses[1] - if data: - data = self.parse_detail(data) - self.populate_addresses(data, 'ipv4') - - data = self.responses[2] - if data: - data = self.parse_detail(data) - self.populate_addresses(data, 'ipv6') - - data = self.responses[3] - if data: - self.facts['neighbors'] = list(self.parse_detail(data)) - - def populate_interfaces(self, data): - for key, value in iteritems(data): - self.facts['interfaces'][key] = value - - def populate_addresses(self, data, family): - for value in data: - key = value['interface'] - if family not in self.facts['interfaces'][key]: - self.facts['interfaces'][key][family] = list() - addr, subnet = value['address'].split("/") - ip = dict(address=addr.strip(), subnet=subnet.strip()) - self.add_ip_address(addr.strip(), family) - self.facts['interfaces'][key][family].append(ip) - - 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 preprocess(self, data): - preprocessed = list() - for line in data.split('\n'): - if len(line) == 0 or line[:5] == 'Flags': - continue - elif not re.match(self.WRAPPED_LINE_RE, line): - preprocessed.append(line) - else: - preprocessed[-1] += line - return preprocessed - - def parse_interfaces(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - parsed = dict(re.findall(self.DETAIL_RE, line)) - if "name" not in parsed: - continue - facts[parsed["name"]] = dict(re.findall(self.DETAIL_RE, line)) - return facts - - def parse_detail(self, data): - data = self.preprocess(data) - for line in data: - parsed = dict(re.findall(self.DETAIL_RE, line)) - if "interface" not in parsed: - continue - yield parsed - - -class Routing(FactsBase): - - COMMANDS = [ - '/routing bgp peer print detail without-paging', - '/routing bgp vpnv4-route print detail without-paging', - '/routing bgp instance print detail without-paging', - '/ip route print detail without-paging', - '/routing ospf instance print detail without-paging', - '/routing ospf neighbor print detail without-paging' - ] - - DETAIL_RE = re.compile(r'([\w\d\-]+)=\"?(\w{3}/\d{2}/\d{4}\s\d{2}:\d{2}:\d{2}|[\w\d\-\.:/]+)') - WRAPPED_LINE_RE = re.compile(r'^\s+(?!\d)') - - def populate(self): - super(Routing, self).populate() - self.facts['bgp_peer'] = dict() - self.facts['bgp_vpnv4_route'] = dict() - self.facts['bgp_instance'] = dict() - self.facts['route'] = dict() - self.facts['ospf_instance'] = dict() - self.facts['ospf_neighbor'] = dict() - data = self.responses[0] - if data: - peer = self.parse_bgp_peer(data) - self.populate_bgp_peer(peer) - data = self.responses[1] - if data: - vpnv4 = self.parse_vpnv4_route(data) - self.populate_vpnv4_route(vpnv4) - data = self.responses[2] - if data: - instance = self.parse_instance(data) - self.populate_bgp_instance(instance) - data = self.responses[3] - if data: - route = self.parse_route(data) - self.populate_route(route) - data = self.responses[4] - if data: - instance = self.parse_instance(data) - self.populate_ospf_instance(instance) - data = self.responses[5] - if data: - instance = self.parse_ospf_neighbor(data) - self.populate_ospf_neighbor(instance) - - def preprocess(self, data): - preprocessed = list() - for line in data.split('\n'): - if len(line) == 0 or line[:5] == 'Flags': - continue - elif not re.match(self.WRAPPED_LINE_RE, line): - preprocessed.append(line) - else: - preprocessed[-1] += line - return preprocessed - - def parse_name(self, data): - match = re.search(r'name=.(\S+\b)', data, re.M) - if match: - return match.group(1) - - def parse_interface(self, data): - match = re.search(r'interface=([\w\d\-]+)', data, re.M) - if match: - return match.group(1) - - def parse_instance_name(self, data): - match = re.search(r'instance=([\w\d\-]+)', data, re.M) - if match: - return match.group(1) - - def parse_routing_mark(self, data): - match = re.search(r'routing-mark=([\w\d\-]+)', data, re.M) - if match: - return match.group(1) - else: - match = 'main' - return match - - def parse_bgp_peer(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_name(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def parse_instance(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_name(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def parse_vpnv4_route(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_interface(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def parse_route(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_routing_mark(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def parse_ospf_instance(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_name(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def parse_ospf_neighbor(self, data): - facts = dict() - data = self.preprocess(data) - for line in data: - name = self.parse_instance_name(line) - facts[name] = dict() - for (key, value) in re.findall(self.DETAIL_RE, line): - facts[name][key] = value - return facts - - def populate_bgp_peer(self, data): - for key, value in iteritems(data): - self.facts['bgp_peer'][key] = value - - def populate_vpnv4_route(self, data): - for key, value in iteritems(data): - self.facts['bgp_vpnv4_route'][key] = value - - def populate_bgp_instance(self, data): - for key, value in iteritems(data): - self.facts['bgp_instance'][key] = value - - def populate_route(self, data): - for key, value in iteritems(data): - self.facts['route'][key] = value - - def populate_ospf_instance(self, data): - for key, value in iteritems(data): - self.facts['ospf_instance'][key] = value - - def populate_ospf_neighbor(self, data): - for key, value in iteritems(data): - self.facts['ospf_neighbor'][key] = value - - -FACT_SUBSETS = dict( - default=Default, - hardware=Hardware, - interfaces=Interfaces, - config=Config, - routing=Routing, -) - -VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) - -warnings = list() - - -def main(): - """main entry point for module execution - """ - argument_spec = dict( - gather_subset=dict(default=['!config'], type='list') - ) - - argument_spec.update(routeros_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - gather_subset = module.params['gather_subset'] - - runable_subsets = set() - exclude_subsets = set() - - for subset in gather_subset: - if subset == 'all': - runable_subsets.update(VALID_SUBSETS) - continue - - if subset.startswith('!'): - subset = subset[1:] - if subset == 'all': - exclude_subsets.update(VALID_SUBSETS) - continue - exclude = True - else: - exclude = False - - if subset not in VALID_SUBSETS: - module.fail_json(msg='Bad subset: %s' % subset) - - if exclude: - exclude_subsets.add(subset) - else: - runable_subsets.add(subset) - - if not runable_subsets: - runable_subsets.update(VALID_SUBSETS) - - runable_subsets.difference_update(exclude_subsets) - runable_subsets.add('default') - - facts = dict() - facts['gather_subset'] = list(runable_subsets) - - instances = list() - for key in runable_subsets: - instances.append(FACT_SUBSETS[key](module)) - - for inst in instances: - inst.populate() - facts.update(inst.facts) - - ansible_facts = dict() - for key, value in iteritems(facts): - key = 'ansible_net_%s' % key - ansible_facts[key] = value - - module.exit_json(ansible_facts=ansible_facts, warnings=warnings) - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/network/slxos/slxos_linkagg.py b/plugins/modules/network/slxos/slxos_linkagg.py index 57cd41d5..69b5db2e 100644 --- a/plugins/modules/network/slxos/slxos_linkagg.py +++ b/plugins/modules/network/slxos/slxos_linkagg.py @@ -53,6 +53,7 @@ description: - Purge links not defined in the I(aggregate) parameter. type: bool + default: false ''' EXAMPLES = """ diff --git a/plugins/modules/panos_admin.py b/plugins/modules/panos_admin.py deleted file mode 120000 index 03f1dfe3..00000000 --- a/plugins/modules/panos_admin.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_admin.py \ No newline at end of file diff --git a/plugins/modules/panos_admpwd.py b/plugins/modules/panos_admpwd.py deleted file mode 120000 index 602a794e..00000000 --- a/plugins/modules/panos_admpwd.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_admpwd.py \ No newline at end of file diff --git a/plugins/modules/panos_cert_gen_ssh.py b/plugins/modules/panos_cert_gen_ssh.py deleted file mode 120000 index ff23e5d7..00000000 --- a/plugins/modules/panos_cert_gen_ssh.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_cert_gen_ssh.py \ No newline at end of file diff --git a/plugins/modules/panos_check.py b/plugins/modules/panos_check.py deleted file mode 120000 index 213384f9..00000000 --- a/plugins/modules/panos_check.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_check.py \ No newline at end of file diff --git a/plugins/modules/panos_commit.py b/plugins/modules/panos_commit.py deleted file mode 120000 index effa4d89..00000000 --- a/plugins/modules/panos_commit.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_commit.py \ No newline at end of file diff --git a/plugins/modules/panos_dag.py b/plugins/modules/panos_dag.py deleted file mode 120000 index a8c23bd3..00000000 --- a/plugins/modules/panos_dag.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_dag.py \ No newline at end of file diff --git a/plugins/modules/panos_dag_tags.py b/plugins/modules/panos_dag_tags.py deleted file mode 120000 index 5dbc7c8f..00000000 --- a/plugins/modules/panos_dag_tags.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_dag_tags.py \ No newline at end of file diff --git a/plugins/modules/panos_import.py b/plugins/modules/panos_import.py deleted file mode 120000 index cccb29a8..00000000 --- a/plugins/modules/panos_import.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_import.py \ No newline at end of file diff --git a/plugins/modules/panos_interface.py b/plugins/modules/panos_interface.py deleted file mode 120000 index bc9f4542..00000000 --- a/plugins/modules/panos_interface.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_interface.py \ No newline at end of file diff --git a/plugins/modules/panos_lic.py b/plugins/modules/panos_lic.py deleted file mode 120000 index 41a6f06f..00000000 --- a/plugins/modules/panos_lic.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_lic.py \ No newline at end of file diff --git a/plugins/modules/panos_loadcfg.py b/plugins/modules/panos_loadcfg.py deleted file mode 120000 index 380a24ee..00000000 --- a/plugins/modules/panos_loadcfg.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_loadcfg.py \ No newline at end of file diff --git a/plugins/modules/panos_match_rule.py b/plugins/modules/panos_match_rule.py deleted file mode 120000 index 29a7c7ac..00000000 --- a/plugins/modules/panos_match_rule.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_match_rule.py \ No newline at end of file diff --git a/plugins/modules/panos_mgtconfig.py b/plugins/modules/panos_mgtconfig.py deleted file mode 120000 index 62639cb4..00000000 --- a/plugins/modules/panos_mgtconfig.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_mgtconfig.py \ No newline at end of file diff --git a/plugins/modules/panos_nat_rule.py b/plugins/modules/panos_nat_rule.py deleted file mode 120000 index ffaa6827..00000000 --- a/plugins/modules/panos_nat_rule.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_nat_rule.py \ No newline at end of file diff --git a/plugins/modules/panos_object.py b/plugins/modules/panos_object.py deleted file mode 120000 index 652b1474..00000000 --- a/plugins/modules/panos_object.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_object.py \ No newline at end of file diff --git a/plugins/modules/panos_op.py b/plugins/modules/panos_op.py deleted file mode 120000 index 75db3222..00000000 --- a/plugins/modules/panos_op.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_op.py \ No newline at end of file diff --git a/plugins/modules/panos_pg.py b/plugins/modules/panos_pg.py deleted file mode 120000 index 2bae9ed1..00000000 --- a/plugins/modules/panos_pg.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_pg.py \ No newline at end of file diff --git a/plugins/modules/panos_query_rules.py b/plugins/modules/panos_query_rules.py deleted file mode 120000 index eda85e3d..00000000 --- a/plugins/modules/panos_query_rules.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_query_rules.py \ No newline at end of file diff --git a/plugins/modules/panos_restart.py b/plugins/modules/panos_restart.py deleted file mode 120000 index 980993b9..00000000 --- a/plugins/modules/panos_restart.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_restart.py \ No newline at end of file diff --git a/plugins/modules/panos_sag.py b/plugins/modules/panos_sag.py deleted file mode 120000 index 241b50a9..00000000 --- a/plugins/modules/panos_sag.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_sag.py \ No newline at end of file diff --git a/plugins/modules/panos_security_rule.py b/plugins/modules/panos_security_rule.py deleted file mode 120000 index 3db5bd03..00000000 --- a/plugins/modules/panos_security_rule.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_security_rule.py \ No newline at end of file diff --git a/plugins/modules/panos_set.py b/plugins/modules/panos_set.py deleted file mode 120000 index a120b896..00000000 --- a/plugins/modules/panos_set.py +++ /dev/null @@ -1 +0,0 @@ -./network/panos/panos_set.py \ No newline at end of file diff --git a/plugins/modules/pn_cluster.py b/plugins/modules/pn_cluster.py deleted file mode 120000 index 0c9b5db2..00000000 --- a/plugins/modules/pn_cluster.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_cluster.py \ No newline at end of file diff --git a/plugins/modules/pn_ospf.py b/plugins/modules/pn_ospf.py deleted file mode 120000 index bf8d4879..00000000 --- a/plugins/modules/pn_ospf.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_ospf.py \ No newline at end of file diff --git a/plugins/modules/pn_ospfarea.py b/plugins/modules/pn_ospfarea.py deleted file mode 120000 index df1d2a6c..00000000 --- a/plugins/modules/pn_ospfarea.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_ospfarea.py \ No newline at end of file diff --git a/plugins/modules/pn_show.py b/plugins/modules/pn_show.py deleted file mode 120000 index 1d6f969b..00000000 --- a/plugins/modules/pn_show.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_show.py \ No newline at end of file diff --git a/plugins/modules/pn_trunk.py b/plugins/modules/pn_trunk.py deleted file mode 120000 index a2c03678..00000000 --- a/plugins/modules/pn_trunk.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_trunk.py \ No newline at end of file diff --git a/plugins/modules/pn_vlag.py b/plugins/modules/pn_vlag.py deleted file mode 120000 index d5b98ecd..00000000 --- a/plugins/modules/pn_vlag.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vlag.py \ No newline at end of file diff --git a/plugins/modules/pn_vlan.py b/plugins/modules/pn_vlan.py deleted file mode 120000 index aa2c098b..00000000 --- a/plugins/modules/pn_vlan.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vlan.py \ No newline at end of file diff --git a/plugins/modules/pn_vrouter.py b/plugins/modules/pn_vrouter.py deleted file mode 120000 index fe01fb14..00000000 --- a/plugins/modules/pn_vrouter.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vrouter.py \ No newline at end of file diff --git a/plugins/modules/pn_vrouterbgp.py b/plugins/modules/pn_vrouterbgp.py deleted file mode 120000 index 2c985cd3..00000000 --- a/plugins/modules/pn_vrouterbgp.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vrouterbgp.py \ No newline at end of file diff --git a/plugins/modules/pn_vrouterif.py b/plugins/modules/pn_vrouterif.py deleted file mode 120000 index 74da3eab..00000000 --- a/plugins/modules/pn_vrouterif.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vrouterif.py \ No newline at end of file diff --git a/plugins/modules/pn_vrouterlbif.py b/plugins/modules/pn_vrouterlbif.py deleted file mode 120000 index 2fcbd596..00000000 --- a/plugins/modules/pn_vrouterlbif.py +++ /dev/null @@ -1 +0,0 @@ -./network/netvisor/pn_vrouterlbif.py \ No newline at end of file diff --git a/plugins/modules/routeros_api.py b/plugins/modules/routeros_api.py deleted file mode 120000 index 65d993b8..00000000 --- a/plugins/modules/routeros_api.py +++ /dev/null @@ -1 +0,0 @@ -./network/routeros/routeros_api.py \ No newline at end of file diff --git a/plugins/modules/routeros_command.py b/plugins/modules/routeros_command.py deleted file mode 120000 index 81f40e66..00000000 --- a/plugins/modules/routeros_command.py +++ /dev/null @@ -1 +0,0 @@ -./network/routeros/routeros_command.py \ No newline at end of file diff --git a/plugins/modules/routeros_facts.py b/plugins/modules/routeros_facts.py deleted file mode 120000 index d4aca7ca..00000000 --- a/plugins/modules/routeros_facts.py +++ /dev/null @@ -1 +0,0 @@ -./network/routeros/routeros_facts.py \ No newline at end of file diff --git a/plugins/terminal/routeros.py b/plugins/terminal/routeros.py deleted file mode 100644 index 78996f28..00000000 --- a/plugins/terminal/routeros.py +++ /dev/null @@ -1,69 +0,0 @@ -# -# (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 . -# -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import json -import re - -from ansible.errors import AnsibleConnectionFailure -from ansible.module_utils._text import to_text, to_bytes -from ansible.plugins.terminal import TerminalBase -from ansible.utils.display import Display - -display = Display() - - -class TerminalModule(TerminalBase): - - ansi_re = [ - # check ECMA-48 Section 5.4 (Control Sequences) - re.compile(br'(\x1b\[\?1h\x1b=)'), - re.compile(br'((?:\x9b|\x1b\x5b)[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e])'), - re.compile(br'\x08.') - ] - - terminal_initial_prompt = [ - br'\x1bZ', - ] - - terminal_initial_answer = b'\x1b/Z' - - terminal_stdout_re = [ - re.compile(br"\x1b<"), - re.compile(br"\[[\w\.]+\@[\w\s\-\.]+\] ?> ?$"), - re.compile(br"Please press \"Enter\" to continue!"), - re.compile(br"Do you want to see the software license\? \[Y\/n\]: ?"), - ] - - terminal_stderr_re = [ - re.compile(br"\nbad command name"), - re.compile(br"\nno such item"), - re.compile(br"\ninvalid value for"), - ] - - def on_open_shell(self): - prompt = self._get_prompt() - try: - if prompt.strip().endswith(b':'): - self._exec_cli_command(b' ') - if prompt.strip().endswith(b'!'): - self._exec_cli_command(b'\n') - except AnsibleConnectionFailure: - raise AnsibleConnectionFailure('unable to bypass license prompt') diff --git a/tests/requirements.yml b/tests/requirements.yml index d03f8807..67c9c9aa 100644 --- a/tests/requirements.yml +++ b/tests/requirements.yml @@ -2,5 +2,4 @@ integration_tests_dependencies: - ansible.netcommon unit_tests_dependencies: - ansible.netcommon -- check_point.mgmt - fortinet.fortios diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 2021f510..6ff67f8f 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -1005,7 +1005,6 @@ plugins/modules/network/netvisor/pn_access_list_ip.py validate-modules:parameter plugins/modules/network/netvisor/pn_admin_service.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_admin_session_timeout.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_admin_syslog.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_cluster.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_connection_stats_settings.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_cpu_class.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_cpu_class.py validate-modules:parameter-type-not-in-doc @@ -1023,9 +1022,6 @@ plugins/modules/network/netvisor/pn_ipv6security_raguard_port.py validate-module plugins/modules/network/netvisor/pn_ipv6security_raguard_vlan.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_log_audit_exception.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_log_audit_exception.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_ospf.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_ospf.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_ospfarea.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_port_config.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_port_config.py validate-modules:required_one_of-unknown plugins/modules/network/netvisor/pn_port_cos_bw.py validate-modules:invalid-ansiblemodule-schema @@ -1034,8 +1030,6 @@ plugins/modules/network/netvisor/pn_prefix_list.py validate-modules:invalid-ansi plugins/modules/network/netvisor/pn_prefix_list_network.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_role.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_role.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_show.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_show.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_snmp_community.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_snmp_community.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_snmp_trap_sink.py validate-modules:invalid-ansiblemodule-schema @@ -1043,12 +1037,8 @@ plugins/modules/network/netvisor/pn_snmp_vacm.py validate-modules:invalid-ansibl plugins/modules/network/netvisor/pn_stp.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_stp_port.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_switch_setup.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_trunk.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_user.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vflow_table_profile.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_vlag.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vlan.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouter.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vrouter_bgp.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vrouter_bgp.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vrouter_bgp_network.py validate-modules:invalid-ansiblemodule-schema @@ -1059,11 +1049,6 @@ plugins/modules/network/netvisor/pn_vrouter_ospf6.py validate-modules:invalid-an plugins/modules/network/netvisor/pn_vrouter_packet_relay.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vrouter_pim_config.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_vrouter_pim_config.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_vrouterbgp.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vtep.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/nos/nos_command.py validate-modules:doc-missing-type plugins/modules/network/nos/nos_command.py validate-modules:parameter-list-no-elements @@ -1096,52 +1081,6 @@ plugins/modules/network/ordnance/ordnance_facts.py validate-modules:parameter-li plugins/modules/network/ordnance/ordnance_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/ordnance/ordnance_facts.py validate-modules:undocumented-parameter plugins/modules/network/ordnance/ordnance_facts.py yamllint:unparsable-with-libyaml -plugins/modules/network/panos/panos_admin.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_admin.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_admpwd.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_check.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_commit.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_commit.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_commit.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_commit.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_dag.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_dag_tags.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_dag_tags.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_dag_tags.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_dag_tags.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_import.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_interface.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_lic.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_lic.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_loadcfg.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_match_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_match_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_match_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_mgtconfig.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_nat_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_nat_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_nat_rule.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_nat_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_object.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_object.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_object.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_object.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_op.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_op.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_pg.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_query_rules.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_query_rules.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_restart.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_sag.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_sag.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_sag.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_security_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_security_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_security_rule.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_security_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_set.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_commit.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_commit.py validate-modules:parameter-list-no-elements plugins/modules/network/radware/vdirect_commit.py validate-modules:parameter-type-not-in-doc @@ -1149,11 +1088,6 @@ plugins/modules/network/radware/vdirect_file.py validate-modules:doc-missing-typ plugins/modules/network/radware/vdirect_file.py validate-modules:parameter-type-not-in-doc plugins/modules/network/radware/vdirect_runnable.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_runnable.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_command.py validate-modules:doc-missing-type -plugins/modules/network/routeros/routeros_command.py validate-modules:parameter-list-no-elements -plugins/modules/network/routeros/routeros_command.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_facts.py validate-modules:parameter-list-no-elements -plugins/modules/network/routeros/routeros_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/slxos/slxos_command.py validate-modules:doc-missing-type plugins/modules/network/slxos/slxos_command.py validate-modules:parameter-list-no-elements plugins/modules/network/slxos/slxos_command.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 2021f510..6ff67f8f 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -1005,7 +1005,6 @@ plugins/modules/network/netvisor/pn_access_list_ip.py validate-modules:parameter plugins/modules/network/netvisor/pn_admin_service.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_admin_session_timeout.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_admin_syslog.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_cluster.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_connection_stats_settings.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_cpu_class.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_cpu_class.py validate-modules:parameter-type-not-in-doc @@ -1023,9 +1022,6 @@ plugins/modules/network/netvisor/pn_ipv6security_raguard_port.py validate-module plugins/modules/network/netvisor/pn_ipv6security_raguard_vlan.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_log_audit_exception.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_log_audit_exception.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_ospf.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_ospf.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_ospfarea.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_port_config.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_port_config.py validate-modules:required_one_of-unknown plugins/modules/network/netvisor/pn_port_cos_bw.py validate-modules:invalid-ansiblemodule-schema @@ -1034,8 +1030,6 @@ plugins/modules/network/netvisor/pn_prefix_list.py validate-modules:invalid-ansi plugins/modules/network/netvisor/pn_prefix_list_network.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_role.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_role.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_show.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_show.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_snmp_community.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_snmp_community.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_snmp_trap_sink.py validate-modules:invalid-ansiblemodule-schema @@ -1043,12 +1037,8 @@ plugins/modules/network/netvisor/pn_snmp_vacm.py validate-modules:invalid-ansibl plugins/modules/network/netvisor/pn_stp.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_stp_port.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_switch_setup.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_trunk.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_user.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vflow_table_profile.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_vlag.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vlan.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouter.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vrouter_bgp.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vrouter_bgp.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vrouter_bgp_network.py validate-modules:invalid-ansiblemodule-schema @@ -1059,11 +1049,6 @@ plugins/modules/network/netvisor/pn_vrouter_ospf6.py validate-modules:invalid-an plugins/modules/network/netvisor/pn_vrouter_packet_relay.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/netvisor/pn_vrouter_pim_config.py validate-modules:doc-required-mismatch plugins/modules/network/netvisor/pn_vrouter_pim_config.py validate-modules:invalid-ansiblemodule-schema -plugins/modules/network/netvisor/pn_vrouterbgp.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:doc-required-mismatch -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_vtep.py validate-modules:invalid-ansiblemodule-schema plugins/modules/network/nos/nos_command.py validate-modules:doc-missing-type plugins/modules/network/nos/nos_command.py validate-modules:parameter-list-no-elements @@ -1096,52 +1081,6 @@ plugins/modules/network/ordnance/ordnance_facts.py validate-modules:parameter-li plugins/modules/network/ordnance/ordnance_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/ordnance/ordnance_facts.py validate-modules:undocumented-parameter plugins/modules/network/ordnance/ordnance_facts.py yamllint:unparsable-with-libyaml -plugins/modules/network/panos/panos_admin.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_admin.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_admpwd.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_check.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_commit.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_commit.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_commit.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_commit.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_dag.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_dag_tags.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_dag_tags.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_dag_tags.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_dag_tags.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_import.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_interface.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_lic.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_lic.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_loadcfg.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_match_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_match_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_match_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_mgtconfig.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_nat_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_nat_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_nat_rule.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_nat_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_object.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_object.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_object.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_object.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_op.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_op.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_pg.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_query_rules.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_query_rules.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_restart.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_sag.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_sag.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_sag.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_security_rule.py validate-modules:doc-missing-type -plugins/modules/network/panos/panos_security_rule.py validate-modules:doc-required-mismatch -plugins/modules/network/panos/panos_security_rule.py validate-modules:parameter-list-no-elements -plugins/modules/network/panos/panos_security_rule.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/panos/panos_set.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_commit.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_commit.py validate-modules:parameter-list-no-elements plugins/modules/network/radware/vdirect_commit.py validate-modules:parameter-type-not-in-doc @@ -1149,11 +1088,6 @@ plugins/modules/network/radware/vdirect_file.py validate-modules:doc-missing-typ plugins/modules/network/radware/vdirect_file.py validate-modules:parameter-type-not-in-doc plugins/modules/network/radware/vdirect_runnable.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_runnable.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_command.py validate-modules:doc-missing-type -plugins/modules/network/routeros/routeros_command.py validate-modules:parameter-list-no-elements -plugins/modules/network/routeros/routeros_command.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_facts.py validate-modules:parameter-list-no-elements -plugins/modules/network/routeros/routeros_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/slxos/slxos_command.py validate-modules:doc-missing-type plugins/modules/network/slxos/slxos_command.py validate-modules:parameter-list-no-elements plugins/modules/network/slxos/slxos_command.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index 4419de1d..fc759b56 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -791,47 +791,14 @@ plugins/modules/network/netscaler/netscaler_servicegroup.py validate-modules:par plugins/modules/network/netscaler/netscaler_ssl_certkey.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_access_list.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_access_list_ip.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_cluster.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_cluster.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_cluster.py validate-modules:missing-main-call plugins/modules/network/netvisor/pn_cpu_class.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_dscp_map.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_fabric_local.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_igmp_snooping.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_ospf.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_ospf.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_ospf.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_ospfarea.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_ospfarea.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_ospfarea.py validate-modules:missing-main-call plugins/modules/network/netvisor/pn_port_config.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_show.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_show.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_show.py validate-modules:missing-main-call plugins/modules/network/netvisor/pn_snmp_community.py validate-modules:parameter-type-not-in-doc plugins/modules/network/netvisor/pn_switch_setup.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_trunk.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_trunk.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_trunk.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_vlag.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vlag.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vlag.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_vlan.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vlan.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vlan.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_vrouter.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vrouter.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vrouter.py validate-modules:missing-main-call plugins/modules/network/netvisor/pn_vrouter_bgp.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/netvisor/pn_vrouterbgp.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vrouterbgp.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vrouterbgp.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vrouterif.py validate-modules:missing-main-call -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:deprecation-mismatch -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:invalid-documentation -plugins/modules/network/netvisor/pn_vrouterlbif.py validate-modules:missing-main-call plugins/modules/network/nos/nos_command.py validate-modules:doc-missing-type plugins/modules/network/nos/nos_command.py validate-modules:parameter-type-not-in-doc plugins/modules/network/nos/nos_config.py validate-modules:doc-missing-type @@ -849,81 +816,12 @@ plugins/modules/network/ordnance/ordnance_facts.py validate-modules:doc-default- plugins/modules/network/ordnance/ordnance_facts.py validate-modules:doc-missing-type plugins/modules/network/ordnance/ordnance_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/ordnance/ordnance_facts.py validate-modules:undocumented-parameter -plugins/modules/network/panos/panos_admin.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_admin.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_admin.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_admpwd.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_admpwd.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_admpwd.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_cert_gen_ssh.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_check.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_check.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_check.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_commit.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_commit.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_commit.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_dag.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_dag.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_dag.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_dag_tags.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_dag_tags.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_dag_tags.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_import.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_import.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_import.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_interface.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_interface.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_interface.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_lic.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_lic.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_lic.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_loadcfg.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_loadcfg.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_loadcfg.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_match_rule.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_match_rule.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_match_rule.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_mgtconfig.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_mgtconfig.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_mgtconfig.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_nat_rule.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_nat_rule.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_nat_rule.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_object.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_object.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_object.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_op.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_op.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_op.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_pg.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_pg.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_pg.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_query_rules.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_query_rules.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_query_rules.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_restart.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_restart.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_restart.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_sag.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_sag.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_sag.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_security_rule.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_security_rule.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_security_rule.py validate-modules:missing-main-call -plugins/modules/network/panos/panos_set.py validate-modules:deprecation-mismatch -plugins/modules/network/panos/panos_set.py validate-modules:invalid-documentation -plugins/modules/network/panos/panos_set.py validate-modules:missing-main-call plugins/modules/network/radware/vdirect_commit.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_commit.py validate-modules:parameter-type-not-in-doc plugins/modules/network/radware/vdirect_file.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_file.py validate-modules:parameter-type-not-in-doc plugins/modules/network/radware/vdirect_runnable.py validate-modules:doc-missing-type plugins/modules/network/radware/vdirect_runnable.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_command.py validate-modules:doc-missing-type -plugins/modules/network/routeros/routeros_command.py validate-modules:parameter-type-not-in-doc -plugins/modules/network/routeros/routeros_facts.py validate-modules:parameter-type-not-in-doc plugins/modules/network/slxos/slxos_command.py validate-modules:doc-missing-type plugins/modules/network/slxos/slxos_command.py validate-modules:parameter-type-not-in-doc plugins/modules/network/slxos/slxos_config.py validate-modules:doc-missing-type diff --git a/tests/unit/plugins/modules/network/check_point/__init__.py b/tests/unit/plugins/modules/network/check_point/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit/plugins/modules/network/routeros/__init__.py b/tests/unit/plugins/modules/network/routeros/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/__init__.py b/tests/unit/plugins/modules/network/routeros/fixtures/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/export_verbose b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/export_verbose deleted file mode 100644 index 0f49fefe..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/export_verbose +++ /dev/null @@ -1,26 +0,0 @@ -# sep/25/2018 10:10:52 by RouterOS 6.42.5 -# software id = 9EER-511K -# -# -# -/interface wireless security-profiles -set [ find default=yes ] supplicant-identity=MikroTik -/tool user-manager customer -set admin access=own-routers,own-users,own-profiles,own-limits,config-payment-gw -/ip address -add address=192.168.88.1/24 comment=defconf interface=ether1 network=192.168.88.0 -/ip dhcp-client -add dhcp-options=hostname,clientid disabled=no interface=ether1 -/system lcd -set contrast=0 enabled=no port=parallel type=24x4 -/system lcd page -set time disabled=yes display-time=5s -set resources disabled=yes display-time=5s -set uptime disabled=yes display-time=5s -set packets disabled=yes display-time=5s -set bits disabled=yes display-time=5s -set version disabled=yes display-time=5s -set identity disabled=yes display-time=5s -set ether1 disabled=yes display-time=5s -/tool user-manager database -set db-path=user-manager diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/interface_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/interface_print_detail_without-paging deleted file mode 100644 index 9ccddb29..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/interface_print_detail_without-paging +++ /dev/null @@ -1,34 +0,0 @@ -Flags: D - dynamic, X - disabled, R - running, S - slave - 0 R name="ether1" default-name="ether1" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:90 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 1 R name="ether2" default-name="ether2" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:91 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 2 R name="ether3" default-name="ether3" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:92 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 3 R name="ether4" default-name="ether4" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:93 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 4 R name="ether5" default-name="ether5" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:94 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 5 R name="ether6" default-name="ether6" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:95 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 6 R name="ether7" default-name="ether7" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:96 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 7 R name="ether8" default-name="ether8" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:97 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 8 R name="ether9" default-name="ether9" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:98 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 - 9 R name="ether10" default-name="ether10" type="ether" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:99 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 -10 R name="pppoe" default-name="pppoe" type="ppp" mtu=1500 actual-mtu=1500 - mac-address=00:1C:42:36:52:00 last-link-up-time=sep/25/2018 06:30:04 - link-downs=0 diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_address_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_address_print_detail_without-paging deleted file mode 100644 index d4fd2bcd..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_address_print_detail_without-paging +++ /dev/null @@ -1,10 +0,0 @@ -Flags: X - disabled, I - invalid, D - dynamic - 0 ;;; defconf - address=192.168.88.1/24 network=192.168.88.0 interface=ether1 - actual-interface=ether1 - - 1 D address=10.37.129.3/24 network=10.37.129.0 interface=ether1 - actual-interface=ether1 - - 2 D address=10.37.0.0/24 network=10.37.0.1 interface=pppoe - actual-interface=pppoe diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_neighbor_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_neighbor_print_detail_without-paging deleted file mode 100644 index 906dfb75..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_neighbor_print_detail_without-paging +++ /dev/null @@ -1,15 +0,0 @@ - 0 interface=ether2-master address=10.37.129.3 address4=10.37.129.3 mac-address=D4:CA:6D:C6:16:4C identity="router1" platform="MikroTik" version="6.42.2 (stable)" unpack=none age=59s - uptime=3w19h11m36s software-id="1234-1234" board="RBwAPG-5HacT2HnD" interface-name="bridge" system-description="MikroTik RouterOS 6.42.2 (stable) RBwAPG-5HacT2HnD" - system-caps="" system-caps-enabled="" - - 1 interface=ether3 address=10.37.129.4 address4=10.37.129.4 mac-address=D4:CA:6D:C6:18:2F identity="router2" platform="MikroTik" version="6.42.2 (stable)" unpack=none age=54s - uptime=3w19h11m30s software-id="1234-1234" board="RBwAPG-5HacT2HnD" ipv6=no interface-name="bridge" system-description="MikroTik RouterOS 6.42.2 (stable) RBwAPG-5HacT2HnD" - system-caps="" system-caps-enabled="" - - 2 interface=ether5 address=10.37.129.5 address4=10.37.129.5 mac-address=B8:69:F4:37:F0:C8 identity="router3" platform="MikroTik" version="6.40.8 (bugfix)" unpack=none age=43s - uptime=3d14h25m31s software-id="1234-1234" board="RB960PGS" interface-name="ether1" system-description="MikroTik RouterOS 6.40.8 (bugfix) RB960PGS" system-caps="" - system-caps-enabled="" - - 3 interface=ether10 address=10.37.129.6 address4=10.37.129.6 mac-address=6C:3B:6B:A1:0B:63 identity="router4" platform="MikroTik" version="6.42.2 (stable)" unpack=none age=54s - uptime=3w6d1h11m44s software-id="1234-1234" board="RBSXTLTE3-7" interface-name="bridge" system-description="MikroTik RouterOS 6.42.2 (stable) RBSXTLTE3-7" system-caps="" - system-caps-enabled="" diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_route_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_route_print_detail_without-paging deleted file mode 100644 index 6c2e558e..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ip_route_print_detail_without-paging +++ /dev/null @@ -1,19 +0,0 @@ -Flags: X - disabled, A - active, D - dynamic, -C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, -B - blackhole, U - unreachable, P - prohibit - 0 ADC dst-address=10.10.66.0/30 pref-src=10.10.66.1 gateway=bridge1 - gateway-status=bridge1 reachable distance=0 scope=10 - routing-mark=altegro - - 2 A S dst-address=0.0.0.0/0 gateway=85.15.75.109 - gateway-status=85.15.75.109 reachable via Internet-VTK distance=1 - scope=30 target-scope=10 - - 3 ADC dst-address=10.10.1.0/30 pref-src=10.10.1.1 gateway=GRE_TYRMA - gateway-status=GRE_TYRMA reachable distance=0 scope=10 - - 4 DC dst-address=10.10.1.4/30 pref-src=10.10.1.5 gateway=RB2011 - gateway-status=RB2011 unreachable distance=255 scope=10 - - 5 ADC dst-address=10.10.2.0/30 pref-src=10.10.2.1 gateway=VLAN_SAT.ROUTER - gateway-status=VLAN_SAT.ROUTER reachable distance=0 scope=10 diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging deleted file mode 100644 index c18e9ea5..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging +++ /dev/null @@ -1,3 +0,0 @@ -Flags: X - disabled, I - invalid, D - dynamic, G - global, L - link-local - 0 DL address=fe80::21c:42ff:fe36:5290/64 from-pool="" interface=ether1 - actual-interface=ether1 eui-64=no advertise=no no-dad=no diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging_no-ipv6 b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging_no-ipv6 deleted file mode 100644 index 0ea34bc0..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/ipv6_address_print_detail_without-paging_no-ipv6 +++ /dev/null @@ -1 +0,0 @@ -bad command name address (line 1 column 7) diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_instance_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_instance_print_detail_without-paging deleted file mode 100644 index 8c560e2a..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_instance_print_detail_without-paging +++ /dev/null @@ -1,10 +0,0 @@ -Flags: * - default, X - disabled - 0 *X name="default" as=65530 router-id=0.0.0.0 redistribute-connected=no - redistribute-static=no redistribute-rip=no redistribute-ospf=no - redistribute-other-bgp=no out-filter="" client-to-client-reflection=yes - ignore-as-path-len=no routing-table="" - - 1 name="MAIN_AS_STARKDV" as=64520 router-id=10.10.50.1 - redistribute-connected=no redistribute-static=no redistribute-rip=no - redistribute-ospf=no redistribute-other-bgp=no out-filter="" - client-to-client-reflection=yes ignore-as-path-len=no routing-table="" diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_peer_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_peer_print_detail_without-paging deleted file mode 100644 index 1ae4f5bc..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_peer_print_detail_without-paging +++ /dev/null @@ -1,13 +0,0 @@ -Flags: X - disabled, E - established - 0 E name="iBGP_BRAS.TYRMA" instance=MAIN_AS_STARKDV remote-address=10.10.100.1 - remote-as=64520 tcp-md5-key="" nexthop-choice=default multihop=no - route-reflect=yes hold-time=3m ttl=default in-filter="" out-filter="" - address-families=ip,l2vpn,vpnv4 update-source=LAN_KHV - default-originate=never remove-private-as=no as-override=no passive=no - use-bfd=yes - - 1 E name="iBGP_BRAS_SAT" instance=MAIN_AS_STARKDV remote-address=10.10.50.230 - remote-as=64520 tcp-md5-key="" nexthop-choice=default multihop=no - route-reflect=yes hold-time=3m ttl=default in-filter="" out-filter="" - address-families=ip default-originate=never remove-private-as=no - as-override=no passive=no use-bfd=yes diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_vpnv4-route_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_vpnv4-route_print_detail_without-paging deleted file mode 100644 index f64fa6d0..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_bgp_vpnv4-route_print_detail_without-paging +++ /dev/null @@ -1,7 +0,0 @@ -Flags: L - label-present - 0 L route-distinguisher=64520:666 dst-address=10.10.66.8/30 gateway=10.10.100.1 - interface=GRE_TYRMA in-label=6136 out-label=6136 bgp-local-pref=100 - bgp-origin=incomplete bgp-ext-communities="RT:64520:666" - - 1 L route-distinguisher=64520:666 dst-address=10.10.66.0/30 interface=bridge1 - in-label=1790 bgp-ext-communities="RT:64520:666" diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_instance_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_instance_print_detail_without-paging deleted file mode 100644 index 96404663..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_instance_print_detail_without-paging +++ /dev/null @@ -1,10 +0,0 @@ -Flags: X - disabled, * - default - 0 * name="default" router-id=10.10.50.1 distribute-default=never redistribute-connected=no - redistribute-static=no redistribute-rip=no redistribute-bgp=no redistribute-other-ospf=no - metric-default=1 metric-connected=20 metric-static=20 metric-rip=20 metric-bgp=auto - metric-other-ospf=auto in-filter=ospf-in out-filter=ospf-out - - 1 name="OSPF_ALTEGRO" router-id=10.10.66.1 distribute-default=never redistribute-connected=no - redistribute-static=no redistribute-rip=no redistribute-bgp=no redistribute-other-ospf=no - metric-default=1 metric-connected=20 metric-static=20 metric-rip=20 metric-bgp=auto - metric-other-ospf=auto in-filter=ospf-in out-filter=ospf-out routing-table=altegro diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_neighbor_print_detail_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_neighbor_print_detail_without-paging deleted file mode 100644 index d683b252..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/routing_ospf_neighbor_print_detail_without-paging +++ /dev/null @@ -1,3 +0,0 @@ -0 instance=default router-id=10.10.100.1 address=10.10.1.2 interface=GRE_TYRMA priority=1 - dr-address=0.0.0.0 backup-dr-address=0.0.0.0 state="Full" state-changes=15 ls-retransmits=0 - ls-requests=0 db-summaries=0 adjacency=6h8m46s diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_identity_print_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_identity_print_without-paging deleted file mode 100644 index d7dc3ff3..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_identity_print_without-paging +++ /dev/null @@ -1 +0,0 @@ - name: MikroTik diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_resource_print_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_resource_print_without-paging deleted file mode 100644 index 79353f79..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_resource_print_without-paging +++ /dev/null @@ -1,16 +0,0 @@ - uptime: 3h28m52s - version: 6.42.5 (stable) - build-time: Jun/26/2018 12:12:08 - free-memory: 988.3MiB - total-memory: 1010.8MiB - cpu: Intel(R) - cpu-count: 2 - cpu-frequency: 2496MHz - cpu-load: 0% - free-hdd-space: 63.4GiB - total-hdd-space: 63.5GiB - write-sect-since-reboot: 4576 - write-sect-total: 4576 - architecture-name: x86 - board-name: x86 - platform: MikroTik diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_routerboard_print_without-paging b/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_routerboard_print_without-paging deleted file mode 100644 index 263c9590..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/routeros_facts/system_routerboard_print_without-paging +++ /dev/null @@ -1,7 +0,0 @@ - routerboard: yes - model: RouterBOARD 3011UiAS - serial-number: 1234567890 - firmware-type: ipq8060 - factory-firmware: 3.41 - current-firmware: 3.41 - upgrade-firmware: 6.42.2 diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/system_package_print b/tests/unit/plugins/modules/network/routeros/fixtures/system_package_print deleted file mode 100644 index 3f806211..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/system_package_print +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - MMM MMM KKK TTTTTTTTTTT KKK - - MMMM MMMM KKK TTTTTTTTTTT KKK - - MMM MMMM MMM III KKK KKK RRRRRR OOOOOO TTT III KKK KKK - - MMM MM MMM III KKKKK RRR RRR OOO OOO TTT III KKKKK - - MMM MMM III KKK KKK RRRRRR OOO OOO TTT III KKK KKK - - MMM MMM III KKK KKK RRR RRR OOOOOO TTT III KKK KKK - - - - MikroTik RouterOS 6.42.5 (c) 1999-2018 http://www.mikrotik.com/ - - -[?] Gives the list of available commands - -command [?] Gives help on the command and list of arguments - - - -[Tab] Completes the command/word. If the input is ambiguous, - - a second [Tab] gives possible options - - - -/ Move up to base level - -.. Move up one level - -/command Use command at the base level - - -Z <[?47l[?7h[?5l[?25h - - - -[admin@MainRouter] > -[admin@MainRouter] > /system routerboard print -[admin@MainRouter] > /system routerboard print - - routerboard: yes - model: 750GL - serial-number: 1234567890AB - firmware-type: ar7240 - factory-firmware: 3.09 - current-firmware: 6.41.2 - upgrade-firmware: 6.42.5 - - - - - -[admin@MainRouter] > -[admin@MainRouter] > /system identity print -[admin@MainRouter] > /system identity print - - name: MikroTik - - - - - -[admin@MainRouter] > -[admin@MainRouter] > /system package print -[admin@MainRouter] > /system package print - -Flags: X - disabled - # NAME VERSION SCHEDULED - 0 routeros-mipsbe 6.42.5 - 1 system 6.42.5 - 2 ipv6 6.42.5 - 3 wireless 6.42.5 - 4 hotspot 6.42.5 - 5 dhcp 6.42.5 - 6 mpls 6.42.5 - 7 routing 6.42.5 - 8 ppp 6.42.5 - 9 security 6.42.5 -10 advanced-tools 6.42.5 - - - - - -[admin@MainRouter] > -[admin@MainRouter] > \ No newline at end of file diff --git a/tests/unit/plugins/modules/network/routeros/fixtures/system_resource_print b/tests/unit/plugins/modules/network/routeros/fixtures/system_resource_print deleted file mode 100644 index 63bc3beb..00000000 --- a/tests/unit/plugins/modules/network/routeros/fixtures/system_resource_print +++ /dev/null @@ -1,17 +0,0 @@ -[admin@RB1100test] /system resource> print - uptime: 2w1d23h34m57s - version: "5.0rc1" - free-memory: 385272KiB - total-memory: 516708KiB - cpu: "e500v2" - cpu-count: 1 - cpu-frequency: 799MHz - cpu-load: 9% - free-hdd-space: 466328KiB - total-hdd-space: 520192KiB - write-sect-since-reboot: 1411 - write-sect-total: 70625 - bad-blocks: 0.2% - architecture-name: "powerpc" - board-name: "RB1100" - platform: "MikroTik" diff --git a/tests/unit/plugins/modules/network/routeros/routeros_module.py b/tests/unit/plugins/modules/network/routeros/routeros_module.py deleted file mode 100644 index 53589092..00000000 --- a/tests/unit/plugins/modules/network/routeros/routeros_module.py +++ /dev/null @@ -1,88 +0,0 @@ -# (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 . - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import os -import json - -from ansible_collections.community.network.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase - - -fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') -fixture_data = {} - - -def load_fixture(name): - path = os.path.join(fixture_path, name) - - if path in fixture_data: - return fixture_data[path] - - with open(path) as f: - data = f.read() - - try: - data = json.loads(data) - except Exception: - pass - - fixture_data[path] = data - return data - - -class TestRouterosModule(ModuleTestCase): - - def execute_module(self, failed=False, changed=False, commands=None, sort=True, defaults=False): - - self.load_fixtures(commands) - - if failed: - result = self.failed() - self.assertTrue(result['failed'], result) - else: - result = self.changed(changed) - self.assertEqual(result['changed'], changed, result) - - if commands is not None: - if sort: - self.assertEqual(sorted(commands), sorted(result['commands']), result['commands']) - else: - self.assertEqual(commands, result['commands'], result['commands']) - - return result - - def failed(self): - with self.assertRaises(AnsibleFailJson) as exc: - self.module.main() - - result = exc.exception.args[0] - self.assertTrue(result['failed'], result) - return result - - def changed(self, changed=False): - with self.assertRaises(AnsibleExitJson) as exc: - self.module.main() - - result = exc.exception.args[0] - self.assertEqual(result['changed'], changed, result) - return result - - def load_fixtures(self, commands=None): - pass diff --git a/tests/unit/plugins/modules/network/routeros/test_routeros_api.py b/tests/unit/plugins/modules/network/routeros/test_routeros_api.py deleted file mode 100644 index c7fc9526..00000000 --- a/tests/unit/plugins/modules/network/routeros/test_routeros_api.py +++ /dev/null @@ -1,266 +0,0 @@ -# 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 . - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import json -import pytest - -from ansible_collections.community.network.tests.unit.compat.mock import patch, MagicMock -from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args, basic, AnsibleExitJson, AnsibleFailJson, ModuleTestCase -from ansible_collections.community.network.plugins.modules.network.routeros import routeros_api - - -class AnsibleExitJson(Exception): - """Exception class to be raised by module.exit_json and caught by the test case""" - pass - - -class AnsibleFailJson(Exception): - """Exception class to be raised by module.fail_json and caught by the test case""" - pass - - -def exit_json(*args, **kwargs): - """function to patch over exit_json; package return data into an exception""" - if 'changed' not in kwargs: - kwargs['changed'] = False - raise AnsibleExitJson(kwargs) - - -def fail_json(*args, **kwargs): - """function to patch over fail_json; package return data into an exception""" - kwargs['failed'] = True - raise AnsibleFailJson(kwargs) - - -# fixtures -class fake_ros_api: - def __init__(self, api, path): - pass - - def path(self, api, path): - fake_bridge = [{".id": "*DC", "name": "b2", "mtu": "auto", "actual-mtu": 1500, - "l2mtu": 65535, "arp": "enabled", "arp-timeout": "auto", - "mac-address": "3A:C1:90:D6:E8:44", "protocol-mode": "rstp", - "fast-forward": "true", "igmp-snooping": "false", - "auto-mac": "true", "ageing-time": "5m", "priority": - "0x8000", "max-message-age": "20s", "forward-delay": "15s", - "transmit-hold-count": 6, "vlan-filtering": "false", - "dhcp-snooping": "false", "running": "true", "disabled": "false"}] - return fake_bridge - - def arbitrary(self, api, path): - def retr(self, *args, **kwargs): - if 'name' not in kwargs.keys(): - raise TrapError(message="no such command") - dummy_test_string = '/interface/bridge add name=unit_test_brige_arbitrary' - result = "/%s/%s add name=%s" % (path[0], path[1], kwargs['name']) - return [result] - return retr - - def add(self, name): - if name == "unit_test_brige_exist": - raise TrapError - return '*A1' - - def remove(self, id): - if id != "*A1": - raise TrapError(message="no such item (4)") - return '*A1' - - def update(self, **kwargs): - if kwargs['.id'] != "*A1" or 'name' not in kwargs.keys(): - raise TrapError(message="no such item (4)") - return ["updated: {'.id': '%s' % kwargs['.id'], 'name': '%s' % kwargs['name']}"] - - def select(self, *args): - dummy_bridge = [{".id": "*A1", "name": "dummy_bridge_A1"}, - {".id": "*A2", "name": "dummy_bridge_A2"}, - {".id": "*A3", "name": "dummy_bridge_A3"}] - - result = [] - for dummy in dummy_bridge: - found = {} - for search in args: - if search in dummy.keys(): - found[search] = dummy[search] - else: - continue - if len(found.keys()) == 2: - result.append(found) - - if result: - return result - else: - return ["no results for 'interface bridge 'query' %s" % ' '.join(args)] - - def select_where(self, api, path): - api_path = Where() - return api_path - - -class Where: - def __init__(self): - pass - - def select(self, *args): - return self - - def where(self, *args): - return ["*A1"] - - -class TrapError(Exception): - def __init__(self, message="failure: already have interface with such name"): - self.message = message - super().__init__(self.message) - - -class Key: - def __init__(self, name): - self.name = name - self.str_return() - - def str_return(self): - return str(self.name) - - -class TestRouterosApiModule(ModuleTestCase): - - def setUp(self): - librouteros = pytest.importorskip("librouteros") - self.module = routeros_api - self.module.connect = MagicMock(new=fake_ros_api) - self.module.Key = MagicMock(new=Key) - self.config_module_args = {"username": "admin", - "password": "pаss", - "hostname": "127.0.0.1", - "path": "interface bridge"} - - self.mock_module_helper = patch.multiple(basic.AnsibleModule, - exit_json=exit_json, - fail_json=fail_json) - self.mock_module_helper.start() - self.addCleanup(self.mock_module_helper.stop) - - def test_module_fail_when_required_args_missing(self): - with self.assertRaises(AnsibleFailJson): - set_module_args({}) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.path) - def test_routeros_api_path(self): - with self.assertRaises(AnsibleExitJson): - set_module_args(self.config_module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.arbitrary) - def test_routeros_api_add(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['add'] = "name=unit_test_brige" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_add_already_exist(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['add'] = "name=unit_test_brige_exist" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_remove(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['remove'] = "*A1" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_remove_no_id(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['remove'] = "*A2" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.arbitrary) - def test_routeros_api_cmd(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['cmd'] = "add name=unit_test_brige_arbitrary" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.arbitrary) - def test_routeros_api_cmd_none_existing_cmd(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['cmd'] = "add NONE_EXIST=unit_test_brige_arbitrary" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_update(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['update'] = ".id=*A1 name=unit_test_brige" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_update_none_existing_id(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['update'] = ".id=*A2 name=unit_test_brige" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_query(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['query'] = ".id name" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api) - def test_routeros_api_query_missing_key(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['query'] = ".id other" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.select_where) - def test_routeros_api_query_and_WHERE(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['query'] = ".id name WHERE name == dummy_bridge_A2" - set_module_args(module_args) - self.module.main() - - @patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_api.ROS_api_module.api_add_path', new=fake_ros_api.select_where) - def test_routeros_api_query_and_WHERE_no_cond(self): - with self.assertRaises(AnsibleExitJson): - module_args = self.config_module_args.copy() - module_args['query'] = ".id name WHERE name =! dummy_bridge_A2" - set_module_args(module_args) - self.module.main() diff --git a/tests/unit/plugins/modules/network/routeros/test_routeros_command.py b/tests/unit/plugins/modules/network/routeros/test_routeros_command.py deleted file mode 100644 index d28f111f..00000000 --- a/tests/unit/plugins/modules/network/routeros/test_routeros_command.py +++ /dev/null @@ -1,113 +0,0 @@ -# (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 . - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import json - -from ansible_collections.community.network.tests.unit.compat.mock import patch -from ansible_collections.community.network.plugins.modules.network.routeros import routeros_command -from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args -from .routeros_module import TestRouterosModule, load_fixture - - -class TestRouterosCommandModule(TestRouterosModule): - - module = routeros_command - - def setUp(self): - super(TestRouterosCommandModule, self).setUp() - - self.mock_run_commands = patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_command.run_commands') - self.run_commands = self.mock_run_commands.start() - - def tearDown(self): - super(TestRouterosCommandModule, self).tearDown() - self.mock_run_commands.stop() - - def load_fixtures(self, commands=None): - - def load_from_file(*args, **kwargs): - module, commands = args - output = list() - - for item in commands: - try: - obj = json.loads(item) - command = obj - except ValueError: - command = item - filename = str(command).replace(' ', '_').replace('/', '') - output.append(load_fixture(filename)) - return output - - self.run_commands.side_effect = load_from_file - - def test_routeros_command_simple(self): - set_module_args(dict(commands=['/system resource print'])) - result = self.execute_module() - self.assertEqual(len(result['stdout']), 1) - self.assertTrue('platform: "MikroTik"' in result['stdout'][0]) - - def test_routeros_command_multiple(self): - set_module_args(dict(commands=['/system resource print', '/system resource print'])) - result = self.execute_module() - self.assertEqual(len(result['stdout']), 2) - self.assertTrue('platform: "MikroTik"' in result['stdout'][0]) - - def test_routeros_command_wait_for(self): - wait_for = 'result[0] contains "MikroTik"' - set_module_args(dict(commands=['/system resource print'], wait_for=wait_for)) - self.execute_module() - - def test_routeros_command_wait_for_fails(self): - wait_for = 'result[0] contains "test string"' - set_module_args(dict(commands=['/system resource print'], wait_for=wait_for)) - self.execute_module(failed=True) - self.assertEqual(self.run_commands.call_count, 10) - - def test_routeros_command_retries(self): - wait_for = 'result[0] contains "test string"' - set_module_args(dict(commands=['/system resource print'], wait_for=wait_for, retries=2)) - self.execute_module(failed=True) - self.assertEqual(self.run_commands.call_count, 2) - - def test_routeros_command_match_any(self): - wait_for = ['result[0] contains "MikroTik"', - 'result[0] contains "test string"'] - set_module_args(dict(commands=['/system resource print'], wait_for=wait_for, match='any')) - self.execute_module() - - def test_routeros_command_match_all(self): - wait_for = ['result[0] contains "MikroTik"', - 'result[0] contains "RB1100"'] - set_module_args(dict(commands=['/system resource print'], wait_for=wait_for, match='all')) - self.execute_module() - - def test_routeros_command_match_all_failure(self): - wait_for = ['result[0] contains "MikroTik"', - 'result[0] contains "test string"'] - commands = ['/system resource print', '/system resource print'] - set_module_args(dict(commands=commands, wait_for=wait_for, match='all')) - self.execute_module(failed=True) - - def test_routeros_command_wait_for_2(self): - wait_for = 'result[0] contains "wireless"' - set_module_args(dict(commands=['/system package print'], wait_for=wait_for)) - self.execute_module() diff --git a/tests/unit/plugins/modules/network/routeros/test_routeros_facts.py b/tests/unit/plugins/modules/network/routeros/test_routeros_facts.py deleted file mode 100644 index bdc82382..00000000 --- a/tests/unit/plugins/modules/network/routeros/test_routeros_facts.py +++ /dev/null @@ -1,342 +0,0 @@ -# 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 . - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -from ansible_collections.community.network.tests.unit.compat.mock import patch -from ansible_collections.community.network.plugins.modules.network.routeros import routeros_facts -from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args -from .routeros_module import TestRouterosModule, load_fixture - - -class TestRouterosFactsModule(TestRouterosModule): - - module = routeros_facts - - def setUp(self): - super(TestRouterosFactsModule, self).setUp() - self.mock_run_commands = patch('ansible_collections.community.network.plugins.modules.network.routeros.routeros_facts.run_commands') - self.run_commands = self.mock_run_commands.start() - - def tearDown(self): - super(TestRouterosFactsModule, self).tearDown() - self.mock_run_commands.stop() - - def load_fixtures(self, commands=None): - def load_from_file(*args, **kwargs): - module = args - commands = kwargs['commands'] - output = list() - - for command in commands: - filename = str(command).split(' | ')[0].replace(' ', '_') - output.append(load_fixture('routeros_facts%s' % filename)) - return output - - self.run_commands.side_effect = load_from_file - - def test_routeros_facts_default(self): - set_module_args(dict(gather_subset='default')) - result = self.execute_module() - self.assertEqual( - result['ansible_facts']['ansible_net_hostname'], 'MikroTik' - ) - self.assertEqual( - result['ansible_facts']['ansible_net_version'], '6.42.5 (stable)' - ) - self.assertEqual( - result['ansible_facts']['ansible_net_model'], 'RouterBOARD 3011UiAS' - ) - self.assertEqual( - result['ansible_facts']['ansible_net_serialnum'], '1234567890' - ) - self.assertEqual( - result['ansible_facts']['ansible_net_arch'], 'x86' - ) - self.assertEqual( - result['ansible_facts']['ansible_net_uptime'], '3h28m52s' - ) - - def test_routeros_facts_hardware(self): - set_module_args(dict(gather_subset='hardware')) - result = self.execute_module() - self.assertEqual( - result['ansible_facts']['ansible_net_spacefree_mb'], 64921.6 - ) - self.assertEqual( - result['ansible_facts']['ansible_net_spacetotal_mb'], 65024.0 - ) - self.assertEqual( - result['ansible_facts']['ansible_net_memfree_mb'], 988.3 - ) - self.assertEqual( - result['ansible_facts']['ansible_net_memtotal_mb'], 1010.8 - ) - - def test_routeros_facts_config(self): - set_module_args(dict(gather_subset='config')) - result = self.execute_module() - self.assertIsInstance( - result['ansible_facts']['ansible_net_config'], str - ) - - def test_routeros_facts_interfaces(self): - set_module_args(dict(gather_subset='interfaces')) - result = self.execute_module() - self.assertIn( - result['ansible_facts']['ansible_net_all_ipv4_addresses'][0], ['10.37.129.3', '10.37.0.0', '192.168.88.1'] - ) - self.assertEqual( - result['ansible_facts']['ansible_net_all_ipv6_addresses'], ['fe80::21c:42ff:fe36:5290'] - ) - self.assertEqual( - result['ansible_facts']['ansible_net_all_ipv6_addresses'][0], - result['ansible_facts']['ansible_net_interfaces']['ether1']['ipv6'][0]['address'] - ) - self.assertEqual( - len(result['ansible_facts']['ansible_net_interfaces'].keys()), 11 - ) - self.assertEqual( - len(result['ansible_facts']['ansible_net_neighbors']), 4 - ) - - def test_routeros_facts_interfaces_no_ipv6(self): - fixture = load_fixture( - 'routeros_facts/ipv6_address_print_detail_without-paging_no-ipv6' - ) - interfaces = self.module.Interfaces(module=self.module) - addresses = interfaces.parse_detail(data=fixture) - result = interfaces.populate_addresses(data=addresses, family='ipv6') - - self.assertEqual(result, None) - - def test_routeros_facts_routing(self): - set_module_args(dict(gather_subset='routing')) - result = self.execute_module() - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['name'], ['iBGP_BRAS.TYRMA'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['instance'], ['MAIN_AS_STARKDV'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remote-address'], ['10.10.100.1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remote-as'], ['64520'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['nexthop-choice'], ['default'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['multihop'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['route-reflect'], ['yes'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['hold-time'], ['3m'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['ttl'], ['default'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['address-families'], ['ip'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['update-source'], ['LAN_KHV'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['default-originate'], ['never'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remove-private-as'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['as-override'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['passive'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['use-bfd'], ['yes'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['route-distinguisher'], ['64520:666'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['dst-address'], ['10.10.66.8/30'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['gateway'], ['10.10.100.1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['interface'], ['GRE_TYRMA'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['in-label'], ['6136'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['out-label'], ['6136'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-local-pref'], ['100'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-origin'], ['incomplete'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-ext-communities'], ['RT:64520:666'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['name'], ['default'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['as'], ['65530'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['router-id'], ['0.0.0.0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-connected'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-static'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-rip'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-ospf'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-other-bgp'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['client-to-client-reflection'], ['yes'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_bgp_instance']['default']['ignore-as-path-len'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['dst-address'], ['10.10.66.0/30'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['pref-src'], ['10.10.66.1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['gateway'], ['bridge1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['gateway-status'], ['bridge1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['distance'], ['0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['scope'], ['10'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_route']['altegro']['routing-mark'], ['altegro'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['name'], ['default'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['router-id'], ['10.10.50.1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['distribute-default'], ['never'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-connected'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-static'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-rip'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-bgp'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-other-ospf'], ['no'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-default'], ['1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-connected'], ['20'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-static'], ['20'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-rip'], ['20'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-bgp'], ['auto'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-other-ospf'], ['auto'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['in-filter'], ['ospf-in'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_instance']['default']['out-filter'], ['ospf-out'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['instance'], ['default'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['router-id'], ['10.10.100.1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['address'], ['10.10.1.2'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['interface'], ['GRE_TYRMA'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['priority'], ['1'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['dr-address'], ['0.0.0.0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['backup-dr-address'], ['0.0.0.0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['state'], ['Full'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['state-changes'], ['15'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['ls-retransmits'], ['0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['ls-requests'], ['0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['db-summaries'], ['0'] - ) - self.assertIn( - result['ansible_facts']['ansible_net_ospf_neighbor']['default']['adjacency'], ['6h8m46s'] - ) diff --git a/tests/utils/shippable/shippable.sh b/tests/utils/shippable/shippable.sh index d2078bec..9c46c00c 100755 --- a/tests/utils/shippable/shippable.sh +++ b/tests/utils/shippable/shippable.sh @@ -68,7 +68,6 @@ cd "${TEST_DIR}" # START: HACK install dependencies retry ansible-galaxy -vvv collection install ansible.netcommon -retry ansible-galaxy -vvv collection install check_point.mgmt retry ansible-galaxy -vvv collection install fortinet.fortios # END: HACK