From 90b090b021e45bf2c6d123563ff5478e41116081 Mon Sep 17 00:00:00 2001 From: Komal Uttamrao Patil Date: Thu, 9 Jul 2020 19:29:51 -0700 Subject: [PATCH] OS9 Ansible Collections (#2) * adding OS9 ansible collections * adding OS9 collections Co-authored-by: Patil --- LICENSE | 201 ++++++ README.md | 54 +- tests/unit/__init__.py => docs/os9_aaa.md | 0 .../compat/__init__.py => docs/os9_acl.md | 0 .../unit/mock/__init__.py => docs/os9_bgp.md | 0 .../__init__.py => docs/os9_copy_config.md | 0 .../network/__init__.py => docs/os9_dcb.md | 0 .../dellos9/__init__.py => docs/os9_dns.md | 0 docs/os9_ecmp.md | 0 docs/os9_interface.md | 0 docs/os9_lag.md | 0 docs/os9_lldp.md | 0 docs/os9_logging.md | 0 docs/os9_ntp.md | 0 docs/os9_prefix_list.md | 0 docs/os9_sflow.md | 0 docs/os9_snmp.md | 0 docs/os9_system.md | 0 docs/os9_users.md | 0 docs/os9_vlan.md | 0 docs/os9_vlt.md | 0 docs/os9_vrf.md | 0 docs/os9_vrrp.md | 0 docs/os9_xstp.md | 0 galaxy.yml | 26 +- playbooks/README.md | 35 + playbooks/datacenter.yaml | 11 + playbooks/group_vars/all | 10 + playbooks/group_vars/spine.yaml | 64 ++ playbooks/host_vars/leaf1.yaml | 61 ++ playbooks/host_vars/leaf2.yaml | 65 ++ playbooks/host_vars/leaf3.yaml | 65 ++ playbooks/host_vars/leaf4.yaml | 61 ++ playbooks/host_vars/spine1.yaml | 61 ++ playbooks/host_vars/spine2.yaml | 60 ++ playbooks/inventory.yaml | 20 + plugins/action/{dellos9.py => os9.py} | 30 +- plugins/cliconf/{dellos9.py => os9.py} | 53 +- plugins/doc_fragments/{dellos9.py => os9.py} | 6 +- plugins/module_utils/network/__init__.py | 0 .../network/{dellos9/dellos9.py => os9.py} | 77 +- .../{dellos9_command.py => os9_command.py} | 107 ++- .../{dellos9_config.py => os9_config.py} | 46 +- .../{dellos9_facts.py => os9_facts.py} | 38 +- plugins/terminal/{dellos9.py => os9.py} | 6 +- roles/os9_aaa/LICENSE | 201 ++++++ roles/os9_aaa/README.md | 334 +++++++++ roles/os9_aaa/defaults/main.yml | 16 + roles/os9_aaa/handlers/main.yml | 2 + roles/os9_aaa/meta/main.yml | 17 + roles/os9_aaa/tasks/main.yml | 17 + roles/os9_aaa/templates/os9_aaa.j2 | 680 ++++++++++++++++++ roles/os9_aaa/tests/inventory.yaml | 20 + roles/os9_aaa/tests/main.os6.yaml | 133 ++++ roles/os9_aaa/tests/test.yaml | 5 + roles/os9_aaa/vars/main.yml | 2 + roles/os9_acl/LICENSE | 201 ++++++ roles/os9_acl/README.md | 139 ++++ roles/os9_acl/defaults/main.yml | 2 + roles/os9_acl/handlers/main.yml | 2 + roles/os9_acl/meta/main.yml | 18 + roles/os9_acl/tasks/main.yml | 16 + roles/os9_acl/templates/os9_acl.j2 | 277 +++++++ roles/os9_acl/tests/inventory.yaml | 20 + roles/os9_acl/tests/main.os9.yaml | 88 +++ roles/os9_acl/tests/test.yaml | 5 + roles/os9_acl/vars/main.yml | 2 + roles/os9_bgp/LICENSE | 201 ++++++ roles/os9_bgp/README.md | 229 ++++++ roles/os9_bgp/defaults/main.yml | 2 + roles/os9_bgp/handlers/main.yml | 2 + roles/os9_bgp/meta/main.yml | 19 + roles/os9_bgp/tasks/main.yml | 16 + roles/os9_bgp/templates/os9_bgp.j2 | 351 +++++++++ roles/os9_bgp/tests/inventory.yaml | 20 + roles/os9_bgp/tests/main.os9.yaml | 97 +++ roles/os9_bgp/tests/test.yaml | 5 + roles/os9_bgp/vars/main.yml | 2 + roles/os9_copy_config/LICENSE | 201 ++++++ roles/os9_copy_config/README.md | 136 ++++ roles/os9_copy_config/defaults/main.yml | 2 + roles/os9_copy_config/handlers/main.yml | 2 + roles/os9_copy_config/meta/main.yml | 20 + roles/os9_copy_config/tasks/main.yml | 7 + .../templates/os9_copy_config.j2 | 3 + roles/os9_copy_config/tests/inventory.yaml | 20 + roles/os9_copy_config/tests/main.os9.yaml | 1 + roles/os9_copy_config/tests/test.yaml | 5 + roles/os9_copy_config/vars/main.yml | 2 + roles/os9_dcb/LICENSE | 201 ++++++ roles/os9_dcb/README.md | 138 ++++ roles/os9_dcb/defaults/main.yml | 2 + roles/os9_dcb/handlers/main.yml | 2 + roles/os9_dcb/meta/main.yml | 17 + roles/os9_dcb/tasks/main.yml | 16 + roles/os9_dcb/templates/os9_dcb.j2 | 216 ++++++ roles/os9_dcb/tests/inventory.yaml | 20 + roles/os9_dcb/tests/main.os9.yaml | 38 + roles/os9_dcb/tests/test.yaml | 5 + roles/os9_dcb/vars/main.yml | 2 + roles/os9_dns/LICENSE | 201 ++++++ roles/os9_dns/README.md | 97 +++ roles/os9_dns/defaults/main.yml | 2 + roles/os9_dns/handlers/main.yml | 2 + roles/os9_dns/meta/main.yml | 17 + roles/os9_dns/tasks/main.yml | 16 + roles/os9_dns/templates/os9_dns.j2 | 111 +++ roles/os9_dns/tests/inventory.yaml | 20 + roles/os9_dns/tests/main.os9.yaml | 40 ++ roles/os9_dns/tests/test.yaml | 5 + roles/os9_dns/vars/main.yml | 2 + roles/os9_ecmp/LICENSE | 201 ++++++ roles/os9_ecmp/README.md | 94 +++ roles/os9_ecmp/defaults/main.yml | 2 + roles/os9_ecmp/handlers/main.yml | 2 + roles/os9_ecmp/meta/main.yml | 17 + roles/os9_ecmp/tasks/main.yml | 17 + roles/os9_ecmp/templates/os9_ecmp.j2 | 62 ++ roles/os9_ecmp/tests/inventory.yaml | 20 + roles/os9_ecmp/tests/main.os9.yaml | 14 + roles/os9_ecmp/tests/test.yaml | 5 + roles/os9_ecmp/vars/main.yml | 3 + roles/os9_interface/LICENSE | 201 ++++++ roles/os9_interface/README.md | 178 +++++ roles/os9_interface/defaults/main.yml | 2 + roles/os9_interface/handlers/main.yml | 2 + roles/os9_interface/meta/main.yml | 18 + roles/os9_interface/tasks/main.yml | 16 + .../os9_interface/templates/os9_interface.j2 | 237 ++++++ roles/os9_interface/tests/inventory.yaml | 20 + roles/os9_interface/tests/main.os9.yaml | 50 ++ roles/os9_interface/tests/test.yaml | 5 + roles/os9_interface/vars/main.yml | 2 + roles/os9_lag/LICENSE | 201 ++++++ roles/os9_lag/README.md | 114 +++ roles/os9_lag/defaults/main.yml | 2 + roles/os9_lag/handlers/main.yml | 2 + roles/os9_lag/meta/main.yml | 18 + roles/os9_lag/tasks/main.yml | 16 + roles/os9_lag/templates/os9_lag.j2 | 114 +++ roles/os9_lag/tests/inventory.yaml | 20 + roles/os9_lag/tests/main.os9.yaml | 21 + roles/os9_lag/tests/test.yaml | 5 + roles/os9_lag/vars/main.yml | 2 + roles/os9_lldp/LICENSE | 201 ++++++ roles/os9_lldp/README.md | 250 +++++++ roles/os9_lldp/defaults/main.yml | 2 + roles/os9_lldp/handlers/main.yml | 2 + roles/os9_lldp/meta/main.yml | 20 + roles/os9_lldp/tasks/main.yml | 16 + roles/os9_lldp/templates/os9_lldp.j2 | 516 +++++++++++++ roles/os9_lldp/tests/inventory.yaml | 20 + roles/os9_lldp/tests/main.os9.yaml | 94 +++ roles/os9_lldp/tests/test.yaml | 6 + roles/os9_lldp/vars/main.yml | 2 + roles/os9_logging/LICENSE | 201 ++++++ roles/os9_logging/README.md | 151 ++++ roles/os9_logging/defaults/main.yml | 2 + roles/os9_logging/handlers/main.yml | 2 + roles/os9_logging/meta/main.yml | 19 + roles/os9_logging/tasks/main.yml | 16 + roles/os9_logging/templates/os9_logging.j2 | 198 +++++ roles/os9_logging/tests/inventory.yaml | 20 + roles/os9_logging/tests/main.os9.yaml | 44 ++ roles/os9_logging/tests/test.yaml | 5 + roles/os9_logging/vars/main.yml | 2 + roles/os9_ntp/LICENSE | 201 ++++++ roles/os9_ntp/README.md | 103 +++ roles/os9_ntp/defaults/main.yml | 2 + roles/os9_ntp/handlers/main.yml | 2 + roles/os9_ntp/meta/main.yml | 18 + roles/os9_ntp/tasks/main.yml | 16 + roles/os9_ntp/templates/os9_ntp.j2 | 41 ++ roles/os9_ntp/tests/inventory.yaml | 20 + roles/os9_ntp/tests/main.os9.yaml | 11 + roles/os9_ntp/tests/test.yaml | 5 + roles/os9_ntp/vars/main.yml | 2 + roles/os9_prefix_list/LICENSE | 201 ++++++ roles/os9_prefix_list/README.md | 115 +++ roles/os9_prefix_list/defaults/main.yml | 2 + roles/os9_prefix_list/handlers/main.yml | 2 + roles/os9_prefix_list/meta/main.yml | 17 + roles/os9_prefix_list/tasks/main.yml | 16 + .../templates/os9_prefix_list.j2 | 79 ++ roles/os9_prefix_list/tests/inventory.yaml | 20 + roles/os9_prefix_list/tests/main.os9.yaml | 33 + roles/os9_prefix_list/tests/test.yaml | 5 + roles/os9_prefix_list/vars/main.yml | 2 + roles/os9_sflow/LICENSE | 201 ++++++ roles/os9_sflow/README.md | 125 ++++ roles/os9_sflow/defaults/main.yml | 2 + roles/os9_sflow/handlers/main.yml | 2 + roles/os9_sflow/meta/main.yml | 18 + roles/os9_sflow/tasks/main.yml | 16 + roles/os9_sflow/templates/os9_sflow.j2 | 143 ++++ roles/os9_sflow/tests/inventory.yaml | 20 + roles/os9_sflow/tests/main.os9.yaml | 35 + roles/os9_sflow/tests/test.yaml | 5 + roles/os9_sflow/vars/main.yml | 2 + roles/os9_snmp/LICENSE | 201 ++++++ roles/os9_snmp/README.md | 197 +++++ roles/os9_snmp/defaults/main.yml | 2 + roles/os9_snmp/handlers/main.yml | 2 + roles/os9_snmp/meta/main.yml | 18 + roles/os9_snmp/tasks/main.yml | 16 + roles/os9_snmp/templates/os9_snmp.j2 | 524 ++++++++++++++ roles/os9_snmp/tests/inventory.yaml | 20 + roles/os9_snmp/tests/main.os9.yaml | 83 +++ roles/os9_snmp/tests/test.yaml | 5 + roles/os9_snmp/vars/main.yml | 2 + roles/os9_system/LICENSE | 201 ++++++ roles/os9_system/README.md | 228 ++++++ roles/os9_system/defaults/main.yml | 2 + roles/os9_system/handlers/main.yml | 2 + roles/os9_system/meta/main.yml | 18 + roles/os9_system/tasks/main.yml | 16 + roles/os9_system/templates/os9_system.j2 | 422 +++++++++++ roles/os9_system/tests/inventory.yaml | 20 + roles/os9_system/tests/main.os9.yaml | 74 ++ roles/os9_system/tests/test.yaml | 5 + roles/os9_system/vars/main.yml | 2 + roles/os9_users/LICENSE | 201 ++++++ roles/os9_users/README.md | 110 +++ roles/os9_users/defaults/main.yml | 2 + roles/os9_users/handlers/main.yml | 2 + roles/os9_users/meta/main.yml | 18 + roles/os9_users/tasks/main.yml | 16 + roles/os9_users/templates/os9_users.j2 | 141 ++++ roles/os9_users/tests/inventory.yaml | 20 + roles/os9_users/tests/main.os9.yaml | 27 + roles/os9_users/tests/test.yaml | 5 + roles/os9_users/vars/main.yml | 2 + roles/os9_vlan/LICENSE | 201 ++++++ roles/os9_vlan/README.md | 110 +++ roles/os9_vlan/defaults/main.yml | 2 + roles/os9_vlan/handlers/main.yml | 2 + roles/os9_vlan/meta/main.yml | 18 + roles/os9_vlan/tasks/main.yml | 16 + roles/os9_vlan/templates/os9_vlan.j2 | 79 ++ roles/os9_vlan/tests/inventory.yaml | 20 + roles/os9_vlan/tests/main.os9.yaml | 20 + roles/os9_vlan/tests/test.yaml | 5 + roles/os9_vlan/vars/main.yml | 2 + roles/os9_vlt/LICENSE | 201 ++++++ roles/os9_vlt/README.md | 138 ++++ roles/os9_vlt/defaults/main.yml | 2 + roles/os9_vlt/handlers/main.yml | 2 + roles/os9_vlt/meta/main.yml | 18 + roles/os9_vlt/tasks/main.yml | 16 + roles/os9_vlt/templates/os9_vlt.j2 | 217 ++++++ roles/os9_vlt/tests/inventory.yaml | 20 + roles/os9_vlt/tests/main.os9.yaml | 39 + roles/os9_vlt/tests/test.yaml | 5 + roles/os9_vlt/vars/main.yml | 2 + roles/os9_vrf/LICENSE | 201 ++++++ roles/os9_vrf/README.md | 125 ++++ roles/os9_vrf/defaults/main.yml | 2 + roles/os9_vrf/handlers/main.yml | 2 + roles/os9_vrf/meta/main.yml | 18 + roles/os9_vrf/tasks/main.yml | 16 + roles/os9_vrf/templates/os9_vrf.j2 | 68 ++ roles/os9_vrf/tests/inventory.yaml | 20 + roles/os9_vrf/tests/main.os9.yaml | 15 + roles/os9_vrf/tests/test.yaml | 5 + roles/os9_vrf/vars/main.yml | 2 + roles/os9_vrrp/LICENSE | 201 ++++++ roles/os9_vrrp/README.md | 153 ++++ roles/os9_vrrp/defaults/main.yml | 2 + roles/os9_vrrp/handlers/main.yml | 2 + roles/os9_vrrp/meta/main.yml | 19 + roles/os9_vrrp/tasks/main.yml | 16 + roles/os9_vrrp/templates/os9_vrrp.j2 | 218 ++++++ roles/os9_vrrp/tests/inventory.yaml | 20 + roles/os9_vrrp/tests/main.os9.yaml | 59 ++ roles/os9_vrrp/tests/test.yaml | 5 + roles/os9_vrrp/vars/main.yml | 2 + roles/os9_xstp/LICENSE | 201 ++++++ roles/os9_xstp/README.md | 130 ++++ roles/os9_xstp/defaults/main.yml | 2 + roles/os9_xstp/handlers/main.yml | 2 + roles/os9_xstp/meta/main.yml | 19 + roles/os9_xstp/tasks/main.yml | 16 + roles/os9_xstp/templates/os9_xstp.j2 | 160 +++++ roles/os9_xstp/tests/inventory.yaml | 20 + roles/os9_xstp/tests/main.os9.yaml | 34 + roles/os9_xstp/tests/test.yaml | 5 + roles/os9_xstp/vars/main.yml | 2 + .../dellos9_config/tests/cli/sublevel.yaml | 43 -- .../tests/cli/sublevel_block.yaml | 62 -- .../tests/cli/sublevel_exact.yaml | 66 -- .../tests/cli/sublevel_strict.yaml | 63 -- .../tests/cli/toplevel_after.yaml | 44 -- .../tests/cli/toplevel_before.yaml | 44 -- .../tests/cli/toplevel_nonidempotent.yaml | 39 - .../targets/dellos9_facts/defaults/main.yaml | 2 - .../targets/dellos9_facts/tasks/main.yaml | 2 - .../dellos9_facts/tests/cli/facts.yaml | 42 -- .../os9_command/defaults/main.yaml | 2 + .../os9_command}/tasks/cli.yaml | 6 +- .../os9_command/os9_command/tasks/main.yaml | 2 + .../os9_command/tests/cli/bad_operator} | 2 +- .../os9_command/tests/cli/contains} | 2 +- .../os9_command/tests/cli/invalid} | 4 +- .../os9_command/tests/cli/output} | 4 +- .../os9_command/tests/cli/show_commands.yaml | 74 ++ .../os9_command/tests/cli/timeout} | 2 +- .../os9_config}/defaults/main.yaml | 0 .../os9_config}/tasks/cli.yaml | 6 +- .../os9_config}/tasks/main.yaml | 1 + .../os9_config/tests/cli/configcommands.yaml | 134 ++++ .../os9_config}/tests/cli/toplevel.yaml | 12 +- .../os9_config/tests/cli/vlan_config.txt | 9 + .../os9_facts}/defaults/main.yaml | 0 .../os9_facts}/tasks/cli.yaml | 7 +- .../os9_facts}/tasks/main.yaml | 0 .../os9_facts/tests/cli/testcases_facts.yaml | 56 ++ tests/unit/compat/builtins.py | 33 - tests/unit/compat/mock.py | 122 ---- tests/unit/compat/unittest.py | 38 - tests/unit/mock/loader.py | 116 --- tests/unit/mock/path.py | 5 - tests/unit/mock/procenv.py | 90 --- tests/unit/mock/vault_helper.py | 39 - tests/unit/mock/yaml_helper.py | 121 ---- tests/unit/modules/conftest.py | 28 - .../show_running-config__grep_hostname | 1 - tests/unit/modules/utils.py | 47 -- tests/unit/requirements.txt | 42 -- tests/units/modules/network/os9/__init__.py | 0 .../os9/fixtures/os9_config_config.cfg} | 0 .../network/os9/fixtures/os9_config_src.cfg} | 0 .../network/os9}/fixtures/show_file-systems | 0 .../network/os9}/fixtures/show_interfaces | 0 .../network/os9}/fixtures/show_inventory | 0 .../network/os9}/fixtures/show_ipv6_interface | 0 .../os9}/fixtures/show_lldp_neighbors_detail | 0 .../fixtures/show_memory__except_Processor | 0 .../network/os9}/fixtures/show_running-config | 0 .../show_running-config__grep_hostname | 1 + .../network/os9}/fixtures/show_version | 0 .../modules/network/os9/os9_module.py} | 8 +- .../modules/network/os9/test_os9_command.py} | 32 +- .../modules/network/os9/test_os9_config.py} | 56 +- .../modules/network/os9/test_os9_facts.py} | 41 +- 344 files changed, 16464 insertions(+), 1408 deletions(-) create mode 100644 LICENSE rename tests/unit/__init__.py => docs/os9_aaa.md (100%) rename tests/unit/compat/__init__.py => docs/os9_acl.md (100%) rename tests/unit/mock/__init__.py => docs/os9_bgp.md (100%) rename tests/unit/modules/__init__.py => docs/os9_copy_config.md (100%) rename tests/unit/modules/network/__init__.py => docs/os9_dcb.md (100%) rename tests/unit/modules/network/dellos9/__init__.py => docs/os9_dns.md (100%) create mode 100644 docs/os9_ecmp.md create mode 100644 docs/os9_interface.md create mode 100644 docs/os9_lag.md create mode 100644 docs/os9_lldp.md create mode 100644 docs/os9_logging.md create mode 100644 docs/os9_ntp.md create mode 100644 docs/os9_prefix_list.md create mode 100644 docs/os9_sflow.md create mode 100644 docs/os9_snmp.md create mode 100644 docs/os9_system.md create mode 100644 docs/os9_users.md create mode 100644 docs/os9_vlan.md create mode 100644 docs/os9_vlt.md create mode 100644 docs/os9_vrf.md create mode 100644 docs/os9_vrrp.md create mode 100644 docs/os9_xstp.md create mode 100644 playbooks/README.md create mode 100644 playbooks/datacenter.yaml create mode 100644 playbooks/group_vars/all create mode 100644 playbooks/group_vars/spine.yaml create mode 100644 playbooks/host_vars/leaf1.yaml create mode 100644 playbooks/host_vars/leaf2.yaml create mode 100644 playbooks/host_vars/leaf3.yaml create mode 100644 playbooks/host_vars/leaf4.yaml create mode 100644 playbooks/host_vars/spine1.yaml create mode 100644 playbooks/host_vars/spine2.yaml create mode 100644 playbooks/inventory.yaml rename plugins/action/{dellos9.py => os9.py} (75%) rename plugins/cliconf/{dellos9.py => os9.py} (66%) rename plugins/doc_fragments/{dellos9.py => os9.py} (95%) create mode 100644 plugins/module_utils/network/__init__.py rename plugins/module_utils/network/{dellos9/dellos9.py => os9.py} (74%) rename plugins/modules/{dellos9_command.py => os9_command.py} (73%) rename plugins/modules/{dellos9_config.py => os9_config.py} (92%) rename plugins/modules/{dellos9_facts.py => os9_facts.py} (96%) rename plugins/terminal/{dellos9.py => os9.py} (96%) create mode 100644 roles/os9_aaa/LICENSE create mode 100644 roles/os9_aaa/README.md create mode 100644 roles/os9_aaa/defaults/main.yml create mode 100644 roles/os9_aaa/handlers/main.yml create mode 100644 roles/os9_aaa/meta/main.yml create mode 100644 roles/os9_aaa/tasks/main.yml create mode 100644 roles/os9_aaa/templates/os9_aaa.j2 create mode 100644 roles/os9_aaa/tests/inventory.yaml create mode 100644 roles/os9_aaa/tests/main.os6.yaml create mode 100644 roles/os9_aaa/tests/test.yaml create mode 100644 roles/os9_aaa/vars/main.yml create mode 100644 roles/os9_acl/LICENSE create mode 100644 roles/os9_acl/README.md create mode 100644 roles/os9_acl/defaults/main.yml create mode 100644 roles/os9_acl/handlers/main.yml create mode 100644 roles/os9_acl/meta/main.yml create mode 100644 roles/os9_acl/tasks/main.yml create mode 100644 roles/os9_acl/templates/os9_acl.j2 create mode 100644 roles/os9_acl/tests/inventory.yaml create mode 100644 roles/os9_acl/tests/main.os9.yaml create mode 100644 roles/os9_acl/tests/test.yaml create mode 100644 roles/os9_acl/vars/main.yml create mode 100644 roles/os9_bgp/LICENSE create mode 100644 roles/os9_bgp/README.md create mode 100644 roles/os9_bgp/defaults/main.yml create mode 100644 roles/os9_bgp/handlers/main.yml create mode 100644 roles/os9_bgp/meta/main.yml create mode 100644 roles/os9_bgp/tasks/main.yml create mode 100644 roles/os9_bgp/templates/os9_bgp.j2 create mode 100644 roles/os9_bgp/tests/inventory.yaml create mode 100644 roles/os9_bgp/tests/main.os9.yaml create mode 100644 roles/os9_bgp/tests/test.yaml create mode 100644 roles/os9_bgp/vars/main.yml create mode 100644 roles/os9_copy_config/LICENSE create mode 100644 roles/os9_copy_config/README.md create mode 100644 roles/os9_copy_config/defaults/main.yml create mode 100644 roles/os9_copy_config/handlers/main.yml create mode 100644 roles/os9_copy_config/meta/main.yml create mode 100644 roles/os9_copy_config/tasks/main.yml create mode 100644 roles/os9_copy_config/templates/os9_copy_config.j2 create mode 100644 roles/os9_copy_config/tests/inventory.yaml create mode 100644 roles/os9_copy_config/tests/main.os9.yaml create mode 100644 roles/os9_copy_config/tests/test.yaml create mode 100644 roles/os9_copy_config/vars/main.yml create mode 100644 roles/os9_dcb/LICENSE create mode 100644 roles/os9_dcb/README.md create mode 100644 roles/os9_dcb/defaults/main.yml create mode 100644 roles/os9_dcb/handlers/main.yml create mode 100644 roles/os9_dcb/meta/main.yml create mode 100644 roles/os9_dcb/tasks/main.yml create mode 100644 roles/os9_dcb/templates/os9_dcb.j2 create mode 100644 roles/os9_dcb/tests/inventory.yaml create mode 100644 roles/os9_dcb/tests/main.os9.yaml create mode 100644 roles/os9_dcb/tests/test.yaml create mode 100644 roles/os9_dcb/vars/main.yml create mode 100644 roles/os9_dns/LICENSE create mode 100644 roles/os9_dns/README.md create mode 100644 roles/os9_dns/defaults/main.yml create mode 100644 roles/os9_dns/handlers/main.yml create mode 100644 roles/os9_dns/meta/main.yml create mode 100644 roles/os9_dns/tasks/main.yml create mode 100644 roles/os9_dns/templates/os9_dns.j2 create mode 100644 roles/os9_dns/tests/inventory.yaml create mode 100644 roles/os9_dns/tests/main.os9.yaml create mode 100644 roles/os9_dns/tests/test.yaml create mode 100644 roles/os9_dns/vars/main.yml create mode 100644 roles/os9_ecmp/LICENSE create mode 100644 roles/os9_ecmp/README.md create mode 100644 roles/os9_ecmp/defaults/main.yml create mode 100644 roles/os9_ecmp/handlers/main.yml create mode 100644 roles/os9_ecmp/meta/main.yml create mode 100644 roles/os9_ecmp/tasks/main.yml create mode 100644 roles/os9_ecmp/templates/os9_ecmp.j2 create mode 100644 roles/os9_ecmp/tests/inventory.yaml create mode 100644 roles/os9_ecmp/tests/main.os9.yaml create mode 100644 roles/os9_ecmp/tests/test.yaml create mode 100644 roles/os9_ecmp/vars/main.yml create mode 100644 roles/os9_interface/LICENSE create mode 100644 roles/os9_interface/README.md create mode 100644 roles/os9_interface/defaults/main.yml create mode 100644 roles/os9_interface/handlers/main.yml create mode 100644 roles/os9_interface/meta/main.yml create mode 100644 roles/os9_interface/tasks/main.yml create mode 100644 roles/os9_interface/templates/os9_interface.j2 create mode 100644 roles/os9_interface/tests/inventory.yaml create mode 100644 roles/os9_interface/tests/main.os9.yaml create mode 100644 roles/os9_interface/tests/test.yaml create mode 100644 roles/os9_interface/vars/main.yml create mode 100644 roles/os9_lag/LICENSE create mode 100644 roles/os9_lag/README.md create mode 100644 roles/os9_lag/defaults/main.yml create mode 100644 roles/os9_lag/handlers/main.yml create mode 100644 roles/os9_lag/meta/main.yml create mode 100644 roles/os9_lag/tasks/main.yml create mode 100644 roles/os9_lag/templates/os9_lag.j2 create mode 100644 roles/os9_lag/tests/inventory.yaml create mode 100644 roles/os9_lag/tests/main.os9.yaml create mode 100644 roles/os9_lag/tests/test.yaml create mode 100644 roles/os9_lag/vars/main.yml create mode 100644 roles/os9_lldp/LICENSE create mode 100644 roles/os9_lldp/README.md create mode 100644 roles/os9_lldp/defaults/main.yml create mode 100644 roles/os9_lldp/handlers/main.yml create mode 100644 roles/os9_lldp/meta/main.yml create mode 100644 roles/os9_lldp/tasks/main.yml create mode 100644 roles/os9_lldp/templates/os9_lldp.j2 create mode 100644 roles/os9_lldp/tests/inventory.yaml create mode 100644 roles/os9_lldp/tests/main.os9.yaml create mode 100644 roles/os9_lldp/tests/test.yaml create mode 100644 roles/os9_lldp/vars/main.yml create mode 100644 roles/os9_logging/LICENSE create mode 100644 roles/os9_logging/README.md create mode 100644 roles/os9_logging/defaults/main.yml create mode 100644 roles/os9_logging/handlers/main.yml create mode 100644 roles/os9_logging/meta/main.yml create mode 100644 roles/os9_logging/tasks/main.yml create mode 100644 roles/os9_logging/templates/os9_logging.j2 create mode 100644 roles/os9_logging/tests/inventory.yaml create mode 100644 roles/os9_logging/tests/main.os9.yaml create mode 100644 roles/os9_logging/tests/test.yaml create mode 100644 roles/os9_logging/vars/main.yml create mode 100644 roles/os9_ntp/LICENSE create mode 100644 roles/os9_ntp/README.md create mode 100644 roles/os9_ntp/defaults/main.yml create mode 100644 roles/os9_ntp/handlers/main.yml create mode 100644 roles/os9_ntp/meta/main.yml create mode 100644 roles/os9_ntp/tasks/main.yml create mode 100644 roles/os9_ntp/templates/os9_ntp.j2 create mode 100644 roles/os9_ntp/tests/inventory.yaml create mode 100644 roles/os9_ntp/tests/main.os9.yaml create mode 100644 roles/os9_ntp/tests/test.yaml create mode 100644 roles/os9_ntp/vars/main.yml create mode 100644 roles/os9_prefix_list/LICENSE create mode 100644 roles/os9_prefix_list/README.md create mode 100644 roles/os9_prefix_list/defaults/main.yml create mode 100644 roles/os9_prefix_list/handlers/main.yml create mode 100644 roles/os9_prefix_list/meta/main.yml create mode 100644 roles/os9_prefix_list/tasks/main.yml create mode 100644 roles/os9_prefix_list/templates/os9_prefix_list.j2 create mode 100644 roles/os9_prefix_list/tests/inventory.yaml create mode 100644 roles/os9_prefix_list/tests/main.os9.yaml create mode 100644 roles/os9_prefix_list/tests/test.yaml create mode 100644 roles/os9_prefix_list/vars/main.yml create mode 100644 roles/os9_sflow/LICENSE create mode 100644 roles/os9_sflow/README.md create mode 100644 roles/os9_sflow/defaults/main.yml create mode 100644 roles/os9_sflow/handlers/main.yml create mode 100644 roles/os9_sflow/meta/main.yml create mode 100644 roles/os9_sflow/tasks/main.yml create mode 100644 roles/os9_sflow/templates/os9_sflow.j2 create mode 100644 roles/os9_sflow/tests/inventory.yaml create mode 100644 roles/os9_sflow/tests/main.os9.yaml create mode 100644 roles/os9_sflow/tests/test.yaml create mode 100644 roles/os9_sflow/vars/main.yml create mode 100644 roles/os9_snmp/LICENSE create mode 100644 roles/os9_snmp/README.md create mode 100644 roles/os9_snmp/defaults/main.yml create mode 100644 roles/os9_snmp/handlers/main.yml create mode 100644 roles/os9_snmp/meta/main.yml create mode 100644 roles/os9_snmp/tasks/main.yml create mode 100644 roles/os9_snmp/templates/os9_snmp.j2 create mode 100644 roles/os9_snmp/tests/inventory.yaml create mode 100644 roles/os9_snmp/tests/main.os9.yaml create mode 100644 roles/os9_snmp/tests/test.yaml create mode 100644 roles/os9_snmp/vars/main.yml create mode 100644 roles/os9_system/LICENSE create mode 100644 roles/os9_system/README.md create mode 100644 roles/os9_system/defaults/main.yml create mode 100644 roles/os9_system/handlers/main.yml create mode 100644 roles/os9_system/meta/main.yml create mode 100644 roles/os9_system/tasks/main.yml create mode 100644 roles/os9_system/templates/os9_system.j2 create mode 100644 roles/os9_system/tests/inventory.yaml create mode 100644 roles/os9_system/tests/main.os9.yaml create mode 100644 roles/os9_system/tests/test.yaml create mode 100644 roles/os9_system/vars/main.yml create mode 100644 roles/os9_users/LICENSE create mode 100644 roles/os9_users/README.md create mode 100644 roles/os9_users/defaults/main.yml create mode 100644 roles/os9_users/handlers/main.yml create mode 100644 roles/os9_users/meta/main.yml create mode 100644 roles/os9_users/tasks/main.yml create mode 100644 roles/os9_users/templates/os9_users.j2 create mode 100644 roles/os9_users/tests/inventory.yaml create mode 100644 roles/os9_users/tests/main.os9.yaml create mode 100644 roles/os9_users/tests/test.yaml create mode 100644 roles/os9_users/vars/main.yml create mode 100644 roles/os9_vlan/LICENSE create mode 100644 roles/os9_vlan/README.md create mode 100644 roles/os9_vlan/defaults/main.yml create mode 100644 roles/os9_vlan/handlers/main.yml create mode 100644 roles/os9_vlan/meta/main.yml create mode 100644 roles/os9_vlan/tasks/main.yml create mode 100644 roles/os9_vlan/templates/os9_vlan.j2 create mode 100644 roles/os9_vlan/tests/inventory.yaml create mode 100644 roles/os9_vlan/tests/main.os9.yaml create mode 100644 roles/os9_vlan/tests/test.yaml create mode 100644 roles/os9_vlan/vars/main.yml create mode 100644 roles/os9_vlt/LICENSE create mode 100644 roles/os9_vlt/README.md create mode 100644 roles/os9_vlt/defaults/main.yml create mode 100644 roles/os9_vlt/handlers/main.yml create mode 100644 roles/os9_vlt/meta/main.yml create mode 100644 roles/os9_vlt/tasks/main.yml create mode 100644 roles/os9_vlt/templates/os9_vlt.j2 create mode 100644 roles/os9_vlt/tests/inventory.yaml create mode 100644 roles/os9_vlt/tests/main.os9.yaml create mode 100644 roles/os9_vlt/tests/test.yaml create mode 100644 roles/os9_vlt/vars/main.yml create mode 100644 roles/os9_vrf/LICENSE create mode 100644 roles/os9_vrf/README.md create mode 100644 roles/os9_vrf/defaults/main.yml create mode 100644 roles/os9_vrf/handlers/main.yml create mode 100644 roles/os9_vrf/meta/main.yml create mode 100644 roles/os9_vrf/tasks/main.yml create mode 100644 roles/os9_vrf/templates/os9_vrf.j2 create mode 100644 roles/os9_vrf/tests/inventory.yaml create mode 100644 roles/os9_vrf/tests/main.os9.yaml create mode 100644 roles/os9_vrf/tests/test.yaml create mode 100644 roles/os9_vrf/vars/main.yml create mode 100644 roles/os9_vrrp/LICENSE create mode 100644 roles/os9_vrrp/README.md create mode 100644 roles/os9_vrrp/defaults/main.yml create mode 100644 roles/os9_vrrp/handlers/main.yml create mode 100644 roles/os9_vrrp/meta/main.yml create mode 100644 roles/os9_vrrp/tasks/main.yml create mode 100644 roles/os9_vrrp/templates/os9_vrrp.j2 create mode 100644 roles/os9_vrrp/tests/inventory.yaml create mode 100644 roles/os9_vrrp/tests/main.os9.yaml create mode 100644 roles/os9_vrrp/tests/test.yaml create mode 100644 roles/os9_vrrp/vars/main.yml create mode 100644 roles/os9_xstp/LICENSE create mode 100644 roles/os9_xstp/README.md create mode 100644 roles/os9_xstp/defaults/main.yml create mode 100644 roles/os9_xstp/handlers/main.yml create mode 100644 roles/os9_xstp/meta/main.yml create mode 100644 roles/os9_xstp/tasks/main.yml create mode 100644 roles/os9_xstp/templates/os9_xstp.j2 create mode 100644 roles/os9_xstp/tests/inventory.yaml create mode 100644 roles/os9_xstp/tests/main.os9.yaml create mode 100644 roles/os9_xstp/tests/test.yaml create mode 100644 roles/os9_xstp/vars/main.yml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/sublevel.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/sublevel_block.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/sublevel_exact.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/sublevel_strict.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/toplevel_after.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/toplevel_before.yaml delete mode 100644 tests/integration/targets/dellos9_config/tests/cli/toplevel_nonidempotent.yaml delete mode 100644 tests/integration/targets/dellos9_facts/defaults/main.yaml delete mode 100644 tests/integration/targets/dellos9_facts/tasks/main.yaml delete mode 100644 tests/integration/targets/dellos9_facts/tests/cli/facts.yaml create mode 100644 tests/integration/targets/os9_command/os9_command/defaults/main.yaml rename tests/integration/targets/{dellos9_command => os9_command/os9_command}/tasks/cli.yaml (70%) create mode 100644 tests/integration/targets/os9_command/os9_command/tasks/main.yaml rename tests/integration/targets/{dellos9_command/tests/cli/bad_operator.yaml => os9_command/os9_command/tests/cli/bad_operator} (95%) rename tests/integration/targets/{dellos9_command/tests/cli/contains.yaml => os9_command/os9_command/tests/cli/contains} (95%) rename tests/integration/targets/{dellos9_command/tests/cli/invalid.yaml => os9_command/os9_command/tests/cli/invalid} (92%) rename tests/integration/targets/{dellos9_command/tests/cli/output.yaml => os9_command/os9_command/tests/cli/output} (93%) create mode 100644 tests/integration/targets/os9_command/os9_command/tests/cli/show_commands.yaml rename tests/integration/targets/{dellos9_command/tests/cli/timeout.yaml => os9_command/os9_command/tests/cli/timeout} (94%) rename tests/integration/targets/{dellos9_command => os9_config/os9_config}/defaults/main.yaml (100%) rename tests/integration/targets/{dellos9_config => os9_config/os9_config}/tasks/cli.yaml (78%) rename tests/integration/targets/{dellos9_config => os9_config/os9_config}/tasks/main.yaml (97%) create mode 100644 tests/integration/targets/os9_config/os9_config/tests/cli/configcommands.yaml rename tests/integration/targets/{dellos9_config => os9_config/os9_config}/tests/cli/toplevel.yaml (76%) create mode 100644 tests/integration/targets/os9_config/os9_config/tests/cli/vlan_config.txt rename tests/integration/targets/{dellos9_config => os9_facts/os9_facts}/defaults/main.yaml (100%) rename tests/integration/targets/{dellos9_facts => os9_facts/os9_facts}/tasks/cli.yaml (57%) rename tests/integration/targets/{dellos9_command => os9_facts/os9_facts}/tasks/main.yaml (100%) create mode 100644 tests/integration/targets/os9_facts/os9_facts/tests/cli/testcases_facts.yaml delete mode 100644 tests/unit/compat/builtins.py delete mode 100644 tests/unit/compat/mock.py delete mode 100644 tests/unit/compat/unittest.py delete mode 100644 tests/unit/mock/loader.py delete mode 100644 tests/unit/mock/path.py delete mode 100644 tests/unit/mock/procenv.py delete mode 100644 tests/unit/mock/vault_helper.py delete mode 100644 tests/unit/mock/yaml_helper.py delete mode 100644 tests/unit/modules/conftest.py delete mode 100644 tests/unit/modules/network/dellos9/fixtures/show_running-config__grep_hostname delete mode 100644 tests/unit/modules/utils.py delete mode 100644 tests/unit/requirements.txt create mode 100644 tests/units/modules/network/os9/__init__.py rename tests/{unit/modules/network/dellos9/fixtures/dellos9_config_config.cfg => units/modules/network/os9/fixtures/os9_config_config.cfg} (100%) rename tests/{unit/modules/network/dellos9/fixtures/dellos9_config_src.cfg => units/modules/network/os9/fixtures/os9_config_src.cfg} (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_file-systems (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_interfaces (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_inventory (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_ipv6_interface (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_lldp_neighbors_detail (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_memory__except_Processor (100%) rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_running-config (100%) create mode 100644 tests/units/modules/network/os9/fixtures/show_running-config__grep_hostname rename tests/{unit/modules/network/dellos9 => units/modules/network/os9}/fixtures/show_version (100%) rename tests/{unit/modules/network/dellos9/dellos9_module.py => units/modules/network/os9/os9_module.py} (92%) rename tests/{unit/modules/network/dellos9/test_dellos9_command.py => units/modules/network/os9/test_os9_command.py} (79%) rename tests/{unit/modules/network/dellos9/test_dellos9_config.py => units/modules/network/os9/test_os9_config.py} (75%) rename tests/{unit/modules/network/dellos9/test_dellos9_facts.py => units/modules/network/os9/test_os9_facts.py} (69%) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dba1a61 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 6cab959..a031268 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,52 @@ -[![GitHub Actions CI/CD build status — Collection test suite](https://github.com/ansible-collection-migration/dellemc_networking.os9/workflows/Collection%20test%20suite/badge.svg?branch=master)](https://github.com/ansible-collection-migration/dellemc_networking.os9/actions?query=workflow%3A%22Collection%20test%20suite%22) +# Ansible Network Collection for Dell EMC OS9 -Ansible Collection: dellemc_networking.os9 -================================================= \ No newline at end of file +## Collection contents +The OS9 Ansible Network Collection includes the Ansible modules, plugins and roles required to work on a Dell EMC OS9 PowerSwitch. It also includes sample playbooks and documents that illustrate how the collection can be used. + +### Ansible modules +The following Ansible modules are part of the OS9 collection: + +- **os9_command.py** — Run commands on remote devices running Dell EMC OS9 + +- **os9_config.py** — Manage configuration sections on remote devices running Dell EMC OS9 + +- **os9_facts.py** — Collect facts from remote devices running Dell EMC OS9 + +### Ansible roles +The roles facilitate provisioning of device running Dell EMC OS9. Some of the roles included in the collection are os9_aaa , os9_bgp, os9_ecmp, and so on. The docs directory in the collection includes documentation for each of the roles part of the collection. + +### Playbooks +The playbooks directory includes sample playbooks that illustrate the usage of OS9 collections for provisioning device running Dell EMC OS9. + +## Collection Installation +Install the latest version of OS9 collection from Ansible Galaxy: + + ansible-galaxy collection install dellemc.os9 + +To install a specific version, a version range identifier must be specified. For example, to install the most recent version that is greater than or equal to 1.0.0 and less than 2.0.0: + + ansible-galaxy collection install 'dellemc.os10:>=1.0.0,<2.0.0' + +## Sample playbook + + - hosts: os9_sw1 + connection: network_cli + collections: + - dellemc.os9 + roles: + - os9_vlan + +> **NOTE**: The environment variable ANSIBLE_NETWORK_GROUP_MODULES should be set to 'os9' for using os9-collections in the playbook. + +## Sample host_vars/os9_sw1.yaml + + hostname: os9_sw1 + # parameters for connection type network_cli + ansible_ssh_user: xxxx + ansible_ssh_pass: xxxx + ansible_network_os: dellemc.os9.os9 + +## Sample inventory.yaml + + [os9] + os9_sw1 ansible_host=100.104.28.119 diff --git a/tests/unit/__init__.py b/docs/os9_aaa.md similarity index 100% rename from tests/unit/__init__.py rename to docs/os9_aaa.md diff --git a/tests/unit/compat/__init__.py b/docs/os9_acl.md similarity index 100% rename from tests/unit/compat/__init__.py rename to docs/os9_acl.md diff --git a/tests/unit/mock/__init__.py b/docs/os9_bgp.md similarity index 100% rename from tests/unit/mock/__init__.py rename to docs/os9_bgp.md diff --git a/tests/unit/modules/__init__.py b/docs/os9_copy_config.md similarity index 100% rename from tests/unit/modules/__init__.py rename to docs/os9_copy_config.md diff --git a/tests/unit/modules/network/__init__.py b/docs/os9_dcb.md similarity index 100% rename from tests/unit/modules/network/__init__.py rename to docs/os9_dcb.md diff --git a/tests/unit/modules/network/dellos9/__init__.py b/docs/os9_dns.md similarity index 100% rename from tests/unit/modules/network/dellos9/__init__.py rename to docs/os9_dns.md diff --git a/docs/os9_ecmp.md b/docs/os9_ecmp.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_interface.md b/docs/os9_interface.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_lag.md b/docs/os9_lag.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_lldp.md b/docs/os9_lldp.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_logging.md b/docs/os9_logging.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_ntp.md b/docs/os9_ntp.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_prefix_list.md b/docs/os9_prefix_list.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_sflow.md b/docs/os9_sflow.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_snmp.md b/docs/os9_snmp.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_system.md b/docs/os9_system.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_users.md b/docs/os9_users.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_vlan.md b/docs/os9_vlan.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_vlt.md b/docs/os9_vlt.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_vrf.md b/docs/os9_vrf.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_vrrp.md b/docs/os9_vrrp.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/os9_xstp.md b/docs/os9_xstp.md new file mode 100644 index 0000000..e69de29 diff --git a/galaxy.yml b/galaxy.yml index e92d1b1..5b58b8a 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,16 +1,16 @@ -namespace: dellemc_networking -name: os9 -version: 0.1.0 -readme: README.md authors: - - Abirami N (github.com/abirami-n) -description: null -license: GPL-3.0-or-later -license_file: COPYING -tags: null +- Senthil Ganesan Ganesan +- Komal Patil dependencies: ansible.netcommon: '>=0.0.1' -repository: https://github.com:ansible-collections/dellemc_networking.os9.git -documentation: https://github.com/ansible-collections/dellemc_networking.os9/tree/master/docs -homepage: https://github.com:ansible-collections/dellemc_networking.os9 -issues: https://github.com:ansible-collections/dellemc_networking.os9 +description: Ansible Network Collections for Dell EMC OS9 +license_file: LICENSE +name: os9 +namespace: dellemc +readme: README.md +tags: [dell, dellemc, os9, emc, networking] +version: 1.0.2 +repository: 'https://github.com:ansible-collections/dellemc.os9' +documentation: 'https://github.com/ansible-collections/dellemc.os9/tree/master/docs' +homepage: 'https://github.com:ansible-collections/dellemc.os9' +issues: 'https://github.com:ansible-collections/dellemc.os9/issues' diff --git a/playbooks/README.md b/playbooks/README.md new file mode 100644 index 0000000..16f9c48 --- /dev/null +++ b/playbooks/README.md @@ -0,0 +1,35 @@ +# Provision CLOS fabric using the Ansible collection for Dell EMC OS9 + +This example describes how to use Ansible to build a CLOS fabric with Dell EMC OS9 switches. The sample topology is a two-tier CLOS fabric with two spines and four leaves connected as mesh. eBGP is running between the two tiers. All switches in spine have the same AS number, and each leaf switch has a unique AS number. All AS numbers used are private. + +For application load-balancing purposes, the same prefix is advertised from multiple leaf switches and uses _BGP multipath relax_ feature. + +![CLOS FABRIC Topology](https://ansible-dellos-docs.readthedocs.io/en/latest/_images/topo.png) + +## Create a simple Ansible playbook + +**Step 1** +Create an inventory file called `inventory.yaml`, then specify the device IP address. + +**Step 2** +Create a group variable file called `group_vars/all`, then define credentials and SNMP variables. + +**Step 3** +Create a group variable file called `group_vars/spine.yaml`, then define credentials, hostname, and BGP neighbors of spine group. + +**Step 4** +Create a host variable file called `host_vars/spine1.yaml`, then define the host, credentials, and transport. +Create a host variable file called `host_vars/spine2.yaml`, then define the host, credentials, and transport. + +Create a host variable file called `host_vars/leaf1.yaml`, then define the host, credentials, and transport. +Create a host variable file called `host_vars/leaf2.yaml`, then define the host, credentials, and transport. +Create a host variable file called `host_vars/leaf3.yaml`, then define the host, credentials, and transport. +Create a host variable file called `host_vars/leaf4.yaml`, then define the host, credentials, and transport. + +**Step 5** +Create a playbook called `datacenter.yaml`. + +**Step 6** +Run the playbook. + +`ansible-playbook -i inventory.yaml datacenter.yaml` \ No newline at end of file diff --git a/playbooks/datacenter.yaml b/playbooks/datacenter.yaml new file mode 100644 index 0000000..f17ebd1 --- /dev/null +++ b/playbooks/datacenter.yaml @@ -0,0 +1,11 @@ +--- +- hosts: datacenter + gather_facts: no + connection: network_cli + collections: + - dellemc.os9 + roles: + - os9_interface + - os9_bgp + - os9_snmp + - os9_system diff --git a/playbooks/group_vars/all b/playbooks/group_vars/all new file mode 100644 index 0000000..c3e4398 --- /dev/null +++ b/playbooks/group_vars/all @@ -0,0 +1,10 @@ +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +build_dir: ../tmp/tmp_os9 + +os9_snmp: + snmp_community: + - name: public + access_mode: ro + state: present diff --git a/playbooks/group_vars/spine.yaml b/playbooks/group_vars/spine.yaml new file mode 100644 index 0000000..b6ab6f4 --- /dev/null +++ b/playbooks/group_vars/spine.yaml @@ -0,0 +1,64 @@ +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 + +os9_system: + hostname: "{{ spine_hostname }}" + +os9_bgp: + asn: 64901 + router_id: "{{ bgp_router_id }}" + best_path: + as_path: ignore + as_path_state: present + med: + - attribute: confed + state: present + neighbor: + - type: ipv4 + remote_asn: "{{ bgp_neigh1_remote_asn }}" + ip: "{{ bgp_neigh1_ip }}" + admin: up + state: present + - type: ipv4 + remote_asn: "{{ bgp_neigh2_remote_asn }}" + ip: "{{ bgp_neigh2_ip }}" + admin: up + state: present + - type: ipv4 + remote_asn: "{{ bgp_neigh3_remote_asn }}" + ip: "{{ bgp_neigh3_ip }}" + admin: up + state: present + - type: ipv4 + remote_asn: "{{ bgp_neigh4_remote_asn }}" + ip: "{{ bgp_neigh4_ip }}" + admin: up + state: present + - type: ipv6 + remote_asn: "{{ bgp_neigh5_remote_asn }}" + ip: "{{ bgp_neigh5_ip }}" + admin: up + state: present + - type: ipv6 + remote_asn: "{{ bgp_neigh6_remote_asn }}" + ip: "{{ bgp_neigh6_ip }}" + admin: up + address_family: + - type: ipv4 + activate: false + state: present + - type: ipv6 + activate: true + state: present + state: present + - type: ipv6 + remote_asn: "{{ bgp_neigh7_remote_asn }}" + ip: "{{ bgp_neigh7_ip }}" + admin: up + state: present + - type: ipv6 + remote_asn: "{{ bgp_neigh8_remote_asn }}" + ip: "{{ bgp_neigh8_ip }}" + admin: up + state: present diff --git a/playbooks/host_vars/leaf1.yaml b/playbooks/host_vars/leaf1.yaml new file mode 100644 index 0000000..2244418 --- /dev/null +++ b/playbooks/host_vars/leaf1.yaml @@ -0,0 +1,61 @@ +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +leaf_hostname: "leaf-1" +os9_system: + hostname: "{{ leaf_hostname }}" + hash_algo: + algo: + - name: ecmp + mode: xor1 + state: present +os9_interface: + TenGigabitEthernet 0/0: + desc: "Connected to Spine 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.1.2/24 + ipv6_and_mask: 2001:100:1:1::2/64 + state_ipv6: present + TenGigabitEthernet 0/1: + desc: "Connected to Spine 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.1.2/24 + ipv6_and_mask: 2001:100:2:1::2/64 + state_ipv6: present +os9_bgp: + asn: 64801 + router_id: 100.0.2.1 + best_path: + as_path: ignore + as_path_state: present + med: + - attribute: confed + state: present + neighbor: + - type: ipv4 + remote_asn: 64901 + ip: 100.1.1.1 + admin: up + state: present + - type: ipv4 + remote_asn: 64901 + ip: 100.2.1.1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:1:1::1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:2:1::1 + admin: up + state: present + state: present diff --git a/playbooks/host_vars/leaf2.yaml b/playbooks/host_vars/leaf2.yaml new file mode 100644 index 0000000..2e5cc58 --- /dev/null +++ b/playbooks/host_vars/leaf2.yaml @@ -0,0 +1,65 @@ +hostname: leaf2 +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +leaf_hostname: "leaf-2" +os9_system: + hostname: "{{ leaf_hostname }}" + hash_algo: + algo: + - name: ecmp + mode: xor1 + state: present +os9_interface: + TenGigabitEthernet 0/0: + desc: "Connected to Spine 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.17.2/24 + ipv6_and_mask: 2001:100:1:11::2/64 + state_ipv6: present + TenGigabitEthernet 0/1: + desc: "Connected to Spine 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.17.2/24 + ipv6_and_mask: 2001:100:2:11::2/64 +os9_bgp: + asn: 64802 + router_id: 100.0.2.2 + best_path: + as_path: ignore + as_path_state: present + med: + - attribute: confed + state: present + neighbor: + - type: ipv4 + remote_asn: 64901 + ip: 100.1.18.1 + admin: up + state: present + - type: ipv4 + remote_asn: 64901 + ip: 100.1.17.1 + admin: up + state: present + - type: ipv4 + remote_asn: 64901 + ip: 100.2.17.1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:1:11::1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:2:11::1 + admin: up + state: present diff --git a/playbooks/host_vars/leaf3.yaml b/playbooks/host_vars/leaf3.yaml new file mode 100644 index 0000000..f14f44e --- /dev/null +++ b/playbooks/host_vars/leaf3.yaml @@ -0,0 +1,65 @@ +hostname: leaf3 +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +leaf_hostname: "leaf-3" +os9_system: + hostname: "{{ leaf_hostname }}" + hash_algo: + algo: + - name: ecmp + mode: xor1 + state: present +os9_interface: + TenGigabitEthernet 0/0: + desc: "Connected to Spine 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.33.2/24 + ipv6_and_mask: 2001:100:1:21::2/64 + state_ipv6: present + TenGigabitEthernet 0/1: + desc: "Connected to Spine 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.33.2/24 + ipv6_and_mask: 2001:100:2:21::2/64 +os9_bgp: + asn: 64803 + router_id: 100.0.2.3 + best_path: + as_path: ignore + as_path_state: present + med: + - attribute: confed + state: present + neighbor: + - type: ipv4 + remote_asn: 64901 + ip: 100.1.33.1 + admin: up + state: present + - type: ipv4 + remote_asn: 64901 + ip: 100.2.33.1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:1:21::1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:1:22::1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:2:21::1 + admin: up + state: present diff --git a/playbooks/host_vars/leaf4.yaml b/playbooks/host_vars/leaf4.yaml new file mode 100644 index 0000000..9fc8ca8 --- /dev/null +++ b/playbooks/host_vars/leaf4.yaml @@ -0,0 +1,61 @@ +hostname: leaf4 +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +leaf_hostname: "leaf-4" +os9_system: + hostname: "{{ leaf_hostname }}" + hash_algo: + algo: + - name: ecmp + mode: xor1 + state: present +os9_interface: + TenGigabitEthernet 0/0: + desc: "Connected to Spine 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.49.2/24 + ipv6_and_mask: 2001:100:1:31::2/64 + state_ipv6: present + TenGigabitEthernet 0/1: + desc: "Connected to Spine 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.49.2/24 + ipv6_and_mask: 2001:100:2:31::2/64 + state_ipv6: present +os9_bgp: + asn: 64804 + router_id: 100.0.2.4 + best_path: + as_path: ignore + as_path_state: present + med: + - attribute: confed + state: present + neighbor: + - type: ipv4 + remote_asn: 64901 + ip: 100.1.49.1 + admin: up + state: present + - type: ipv4 + remote_asn: 64901 + ip: 100.2.49.1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:1:31::1 + admin: up + state: present + - type: ipv6 + remote_asn: 64901 + ip: 2001:100:2:31::1 + admin: up + state: present diff --git a/playbooks/host_vars/spine1.yaml b/playbooks/host_vars/spine1.yaml new file mode 100644 index 0000000..9967d33 --- /dev/null +++ b/playbooks/host_vars/spine1.yaml @@ -0,0 +1,61 @@ +hostname: spine1 +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +spine_hostname: "spine-1" + +os9_interface: + TenGigabitEthernet 0/2: + desc: "Connected to leaf 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.1.1/24 + ipv6_and_mask: 2001:100:1:1::1/64 + state_ipv6: present + TenGigabitEthernet 0/3: + desc: "Connected to leaf 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.33.1/24 + ipv6_and_mask: 2001:100:1:21::1/64 + state_ipv6: present + TenGigabitEthernet 0/4: + desc: "Connected to leaf 3" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.17.1/24 + ipv6_and_mask: 2001:100:1:11::1/64 + state_ipv6: present + TenGigabitEthernet 0/5: + desc: "Connected to leaf 4" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.1.49.1/24 + ipv6_and_mask: 2001:100:1:31::1/64 + state_ipv6: present + +bgp_router_id: "100.0.1.1" +bgp_neigh1_remote_asn: 64801 +bgp_neigh1_ip: "100.1.1.2" +bgp_neigh2_remote_asn: 64803 +bgp_neigh2_ip: "100.1.33.2" +bgp_neigh3_remote_asn: 64802 +bgp_neigh3_ip: "100.1.17.2" +bgp_neigh4_remote_asn: 64804 +bgp_neigh4_ip: "100.1.49.2" +bgp_neigh5_remote_asn: 64801 +bgp_neigh5_ip: "2001:100:1:1::2" +bgp_neigh6_remote_asn: 64802 +bgp_neigh6_ip: "2001:100:1:11::2" +bgp_neigh7_remote_asn: 64803 +bgp_neigh7_ip: "2001:100:1:21::2" +bgp_neigh8_remote_asn: 64804 +bgp_neigh8_ip: "2001:100:1:31::2" diff --git a/playbooks/host_vars/spine2.yaml b/playbooks/host_vars/spine2.yaml new file mode 100644 index 0000000..218d647 --- /dev/null +++ b/playbooks/host_vars/spine2.yaml @@ -0,0 +1,60 @@ +hostname: spine2 +ansible_ssh_user: xxxxx +ansible_ssh_pass: xxxxx +ansible_network_os: dellemc.os9.os9 +spine_hostname: "spine-2" +os9_interface: + TenGigabitEthernet 0/6: + desc: "Connected to leaf 1" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.1.1/24 + ipv6_and_mask: 2001:100:2:1::1/64 + state_ipv6: present + TenGigabitEthernet 0/7: + desc: "Connected to leaf 2" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.17.1/24 + ipv6_and_mask: 2001:100:2:11::1/64 + state_ipv6: present + TenGigabitEthernet 0/8: + desc: "Connected to leaf 3" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.33.1/24 + ipv6_and_mask: 2001:100:2:21::1/64 + state_ipv6: present + TenGigabitEthernet 0/9: + desc: "Connected to leaf 4" + mtu: 9216 + portmode: + admin: up + switchport: False + ip_and_mask: 100.2.49.1/24 + ipv6_and_mask: 2001:100:2:31::1/64 + state_ipv6: present + +bgp_router_id: "100.0.1.2" +bgp_neigh1_remote_asn: 64801 +bgp_neigh1_ip: "100.2.1.2" +bgp_neigh2_remote_asn: 64802 +bgp_neigh2_ip: "100.2.33.2" +bgp_neigh3_remote_asn: 64803 +bgp_neigh3_ip: "100.2.17.2" +bgp_neigh4_remote_asn: 64804 +bgp_neigh4_ip: "100.2.49.2" +bgp_neigh5_remote_asn: 64801 +bgp_neigh5_ip: "2001:100:2:1::2" +bgp_neigh6_remote_asn: 64802 +bgp_neigh6_ip: "2001:100:2:11::2" +bgp_neigh7_remote_asn: 64803 +bgp_neigh7_ip: "2001:100:2:21::2" +bgp_neigh8_remote_asn: 64804 +bgp_neigh8_ip: "2001:100:2:31::2" diff --git a/playbooks/inventory.yaml b/playbooks/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/playbooks/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/plugins/action/dellos9.py b/plugins/action/os9.py similarity index 75% rename from plugins/action/dellos9.py rename to plugins/action/os9.py index 7e18a5f..6b266ca 100644 --- a/plugins/action/dellos9.py +++ b/plugins/action/os9.py @@ -1,7 +1,7 @@ # -# (c) 2016 Red Hat Inc. +# (c) 2020 Red Hat Inc. # -# Copyright (c) 2017 Dell Inc. +# Copyright (c) 2020 Dell Inc. # # This file is part of Ansible # @@ -25,9 +25,11 @@ import sys import copy from ansible import constants as C +from ansible.module_utils._text import to_text +from ansible.module_utils.connection import Connection from ansible_collections.ansible.netcommon.plugins.action.network import ActionModule as ActionNetworkModule from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import dellos9_provider_spec +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import os9_provider_spec from ansible.utils.display import Display display = Display() @@ -39,7 +41,7 @@ class ActionModule(ActionNetworkModule): del tmp # tmp no longer has any effect module_name = self._task.action.split('.')[-1] - self._config_module = True if module_name == 'dellos9_config' else False + self._config_module = True if module_name == 'os9_config' else False socket_path = None persistent_connection = self._play_context.connection.split('.')[-1] @@ -49,10 +51,10 @@ class ActionModule(ActionNetworkModule): display.warning('provider is unnecessary when using network_cli and will be ignored') del self._task.args['provider'] elif self._play_context.connection == 'local': - provider = load_provider(dellos9_provider_spec, self._task.args) + provider = load_provider(os9_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' - pc.network_os = 'dellos9' + pc.network_os = 'dellemc.os9.os9' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user @@ -65,7 +67,7 @@ class ActionModule(ActionNetworkModule): pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() @@ -77,5 +79,17 @@ class ActionModule(ActionNetworkModule): task_vars['ansible_socket'] = socket_path + # make sure we are in the right cli context which should be + # enable mode and not config module + if socket_path is None: + socket_path = self._connection.socket_path + + conn = Connection(socket_path) + out = conn.get_prompt() + while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): + display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) + conn.send_command('exit') + out = conn.get_prompt() + result = super(ActionModule, self).run(task_vars=task_vars) - return result + return result \ No newline at end of file diff --git a/plugins/cliconf/dellos9.py b/plugins/cliconf/os9.py similarity index 66% rename from plugins/cliconf/dellos9.py rename to plugins/cliconf/os9.py index b360807..dc53297 100644 --- a/plugins/cliconf/dellos9.py +++ b/plugins/cliconf/os9.py @@ -1,7 +1,7 @@ # -# (c) 2017 Red Hat Inc. +# (c) 2020 Red Hat Inc. # -# (c) 2017 Dell EMC. +# (c) 2020 Dell EMC. # # This file is part of Ansible # @@ -21,23 +21,22 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = """ --- -cliconf: dellos9 -short_description: Use dellos9 cliconf to run command on Dell OS9 platform +cliconf: os9 +short_description: Use os9 cliconf to run command on Dell OS9 platform description: - - This dellos9 plugin provides low level abstraction apis for + - This os9 plugin provides low level abstraction apis for sending and receiving CLI commands from Dell OS9 network devices. -''' +version_added: 2.5 +""" import re import json from itertools import chain -from ansible.errors import AnsibleConnectionFailure from ansible.module_utils._text import to_bytes, to_text -from ansible.module_utils.common._collections_compat import Mapping from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list from ansible.plugins.cliconf import CliconfBase, enable_mode @@ -47,7 +46,7 @@ class Cliconf(CliconfBase): def get_device_info(self): device_info = {} - device_info['network_os'] = 'dellos9' + device_info['network_os'] = 'dellemc.os9.os9' reply = self.get('show version') data = to_text(reply, errors='surrogate_or_strict').strip() @@ -87,36 +86,4 @@ class Cliconf(CliconfBase): def get_capabilities(self): result = super(Cliconf, self).get_capabilities() - return json.dumps(result) - - def run_commands(self, commands=None, check_rc=True): - if commands is None: - raise ValueError("'commands' value is required") - - responses = list() - for cmd in to_list(commands): - if not isinstance(cmd, Mapping): - cmd = {'command': cmd} - - output = cmd.pop('output', None) - if output: - raise ValueError("'output' value %s is not supported for run_commands" % output) - - try: - out = self.send_command(**cmd) - except AnsibleConnectionFailure as e: - if check_rc: - raise - out = getattr(e, 'err', to_text(e)) - - responses.append(out) - - return responses - - def set_cli_prompt_context(self): - """ - Make sure we are in the operational cli mode - :return: None - """ - if self._connection.connected: - self._update_cli_prompt_context(config_context=')#') + return json.dumps(result) \ No newline at end of file diff --git a/plugins/doc_fragments/dellos9.py b/plugins/doc_fragments/os9.py similarity index 95% rename from plugins/doc_fragments/dellos9.py rename to plugins/doc_fragments/os9.py index e65e53c..056c31f 100644 --- a/plugins/doc_fragments/dellos9.py +++ b/plugins/doc_fragments/os9.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -# Copyright: (c) 2015, Peter Sprygada -# Copyright: (c) 2016, Dell Inc. +# Copyright: (c) 2020, Peter Sprygada +# Copyright: (c) 2020, Dell Inc. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -55,4 +55,4 @@ options: default: 10 notes: - For more information on using Ansible to manage Dell EMC Network devices see U(https://www.ansible.com/ansible-dell-networking). -''' +''' \ No newline at end of file diff --git a/plugins/module_utils/network/__init__.py b/plugins/module_utils/network/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugins/module_utils/network/dellos9/dellos9.py b/plugins/module_utils/network/os9.py similarity index 74% rename from plugins/module_utils/network/dellos9/dellos9.py rename to plugins/module_utils/network/os9.py index cdbd1ad..5b0d396 100644 --- a/plugins/module_utils/network/dellos9/dellos9.py +++ b/plugins/module_utils/network/os9.py @@ -1,8 +1,8 @@ # -# (c) 2015 Peter Sprygada, -# (c) 2017 Red Hat, Inc +# (c) 2020 Peter Sprygada, +# (c) 2020 Red Hat, Inc # -# Copyright (c) 2016 Dell Inc. +# Copyright (c) 2020 Dell Inc. # # This code is part of Ansible, but is an independent component. # This particular file snippet, and this file snippet only, is BSD licensed. @@ -29,12 +29,12 @@ # 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. # -import json +import re from ansible.module_utils._text import to_text 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, exec_command +from ansible.module_utils.network.common.utils import to_list, ComplexList +from ansible.module_utils.connection import exec_command from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, ConfigLine _DEVICE_CONFIGS = {} @@ -45,7 +45,7 @@ WARNING_PROMPTS_RE = [ r"[\r\n]?\[yes/no\]:\s?$" ] -dellos9_provider_spec = { +os9_provider_spec = { 'host': dict(), 'port': dict(type='int'), 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), @@ -55,10 +55,10 @@ dellos9_provider_spec = { 'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True), 'timeout': dict(type='int'), } -dellos9_argument_spec = { - 'provider': dict(type='dict', options=dellos9_provider_spec), +os9_argument_spec = { + 'provider': dict(type='dict', options=os9_provider_spec), } -dellos9_top_spec = { +os9_top_spec = { 'host': dict(removed_in_version=2.9), 'port': dict(removed_in_version=2.9, type='int'), 'username': dict(removed_in_version=2.9), @@ -68,36 +68,7 @@ dellos9_top_spec = { 'auth_pass': dict(removed_in_version=2.9, no_log=True), 'timeout': dict(removed_in_version=2.9, type='int'), } -dellos9_argument_spec.update(dellos9_top_spec) - - -def get_provider_argspec(): - return dellos9_provider_spec - - -def get_connection(module): - if hasattr(module, '_dellos9_connection'): - return module._dellos9_connection - - capabilities = get_capabilities(module) - network_api = capabilities.get('network_api') - if network_api == 'cliconf': - module._dellos9_connection = Connection(module._socket_path) - else: - module.fail_json(msg='Invalid connection type %s' % network_api) - - return module._dellos9_connection - - -def get_capabilities(module): - if hasattr(module, '_dellos9_capabilities'): - return module._dellos9_capabilities - try: - capabilities = Connection(module._socket_path).get_capabilities() - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - module._dellos9_capabilities = json.loads(capabilities) - return module._dellos9_capabilities +os9_argument_spec.update(os9_top_spec) def check_args(module, warnings): @@ -122,12 +93,26 @@ def get_config(module, flags=None): 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): - connection = get_connection(module) - try: - return connection.run_commands(commands=commands, check_rc=check_rc) - except ConnectionError as exc: - module.fail_json(msg=to_text(exc)) + responses = list() + commands = to_commands(module, to_list(commands)) + for cmd in commands: + cmd = module.jsonify(cmd) + rc, out, err = exec_command(module, cmd) + if check_rc and rc != 0: + module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc) + responses.append(to_text(out, errors='surrogate_or_strict')) + return responses def load_config(module, commands): @@ -163,4 +148,4 @@ def get_sublevel_config(running_config, module): indent = 1 sublevel_config = '\n'.join(current_config_contents) - return sublevel_config + return sublevel_config \ No newline at end of file diff --git a/plugins/modules/dellos9_command.py b/plugins/modules/os9_command.py similarity index 73% rename from plugins/modules/dellos9_command.py rename to plugins/modules/os9_command.py index 9b4d77f..c9f7afb 100644 --- a/plugins/modules/dellos9_command.py +++ b/plugins/modules/os9_command.py @@ -1,8 +1,8 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright: (c) 2015, Peter Sprygada -# Copyright: (c) 2016, Dell Inc. +# Copyright: (c) 2020, Peter Sprygada +# Copyright: (c) 2020, Dell Inc. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -14,9 +14,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} -DOCUMENTATION = ''' +DOCUMENTATION = """ --- -module: dellos9_command +module: os9_command +version_added: "2.2" author: "Dhivya P (@dhivyap)" short_description: Run commands on remote devices running Dell OS9 description: @@ -25,22 +26,16 @@ description: argument that will cause the module to wait for a specific condition before returning or timing out if the condition is not met. - This module does not support running commands in configuration mode. - Please use M(dellos9_config) to configure Dell OS9 devices. -extends_documentation_fragment: -- dellemc_networking.os9.dellos9 - + Please use M(os9_config) to configure Dell OS9 devices. +extends_documentation_fragment: os9 options: commands: description: - - List of commands to send to the remote dellos9 device over the + - List of commands to send to the remote os9 device over the configured provider. The resulting output from the command is returned. If the I(wait_for) argument is provided, the module is not returned until the condition is satisfied or - the number of retries has expired. If a command sent to the - device requires answering a prompt, it is possible to pass - a dict containing I(command), I(answer) and I(prompt). - Common answers are 'yes' or "\r" (carriage return, must be - double quotes). See examples. + the number of retries has expired. type: list required: true wait_for: @@ -48,9 +43,10 @@ options: - 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. + within the configured number of I(retries), the task fails. See examples. type: list + version_added: "2.2" match: description: - The I(match) argument is used in conjunction with the @@ -61,7 +57,8 @@ options: satisfied. type: str default: all - choices: [ 'all', 'any' ] + choices: [ all, any ] + version_added: "2.5" retries: description: - Specifies the number of retries a command should be tried @@ -78,49 +75,36 @@ options: trying the command again. type: int default: 1 - notes: - This module requires Dell OS9 version 9.10.0.1P13 or above. - - This module requires to increase the ssh connection rate limit. Use the following command I(ip ssh connection-rate-limit 60) - to configure the same. This can be done via M(dellos9_config) module + to configure the same. This can be done via M(os9_config) module as well. - -''' +""" EXAMPLES = """ tasks: - name: run show version on remote devices - dellos9_command: + os9_command: commands: show version - - name: run show version and check to see if output contains OS9 - dellos9_command: + os9_command: commands: show version wait_for: result[0] contains OS9 - - name: run multiple commands on remote nodes - dellos9_command: + os9_command: commands: - show version - show interfaces - - name: run multiple commands and evaluate the output - dellos9_command: + os9_command: commands: - show version - show interfaces wait_for: - result[0] contains OS9 - result[1] contains Loopback - - - name: run commands that require answering a prompt - dellos9_command: - commands: - - command: 'copy running-config startup-config' - prompt: '[confirm yes/no]: ?$' - answer: 'yes' """ RETURN = """ @@ -147,26 +131,39 @@ warnings: """ import time -from ansible.module_utils._text import to_text from ansible.module_utils.basic import AnsibleModule +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import run_commands +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import os9_argument_spec, check_args +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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import transform_commands, to_lines -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import run_commands -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args +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 parse_commands(module, warnings): - commands = transform_commands(module) - - if module.check_mode: - for item in list(commands): - if not item['command'].startswith('show'): - warnings.append( - 'Only show commands are supported when using check mode, not ' - 'executing %s' % item['command'] - ) - commands.remove(item) - + command = ComplexList(dict( + command=dict(key=True), + prompt=dict(), + answer=dict() + ), module) + commands = command(module.params['commands']) + for index, item in enumerate(commands): + if module.check_mode and not item['command'].startswith('show'): + warnings.append( + 'only show commands are supported when using check mode, not ' + 'executing `%s`' % item['command'] + ) + elif item['command'].startswith('conf'): + module.fail_json( + msg='os9_command does not support running config mode ' + 'commands. Please use os9_config instead' + ) return commands @@ -184,7 +181,7 @@ def main(): interval=dict(default=1, type='int') ) - argument_spec.update(dellos9_argument_spec) + argument_spec.update(os9_argument_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) @@ -197,11 +194,8 @@ def main(): result['warnings'] = warnings wait_for = module.params['wait_for'] or list() + conditionals = [Conditional(c) for c in wait_for] - try: - conditionals = [Conditional(c) for c in wait_for] - except AttributeError as exc: - module.fail_json(msg=to_text(exc)) retries = module.params['retries'] interval = module.params['interval'] match = module.params['match'] @@ -228,6 +222,7 @@ def main(): module.fail_json(msg=msg, failed_conditions=failed_conditions) result.update({ + 'changed': False, 'stdout': responses, 'stdout_lines': list(to_lines(responses)) }) @@ -236,4 +231,4 @@ def main(): if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/plugins/modules/dellos9_config.py b/plugins/modules/os9_config.py similarity index 92% rename from plugins/modules/dellos9_config.py rename to plugins/modules/os9_config.py index 16d92ef..80d507f 100644 --- a/plugins/modules/dellos9_config.py +++ b/plugins/modules/os9_config.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -# (c) 2015 Peter Sprygada, -# Copyright (c) 2016 Dell Inc. +# (c) 2020 Peter Sprygada, +# Copyright (c) 2020 Dell Inc. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function @@ -13,9 +13,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.1', 'supported_by': 'community'} -DOCUMENTATION = ''' +DOCUMENTATION = """ --- -module: dellos9_config +module: os9_config +version_added: "2.2" author: "Dhivya P (@dhivyap)" short_description: Manage Dell EMC Networking OS9 configuration sections description: @@ -23,9 +24,7 @@ description: for segmenting configuration into sections. This module provides an implementation for working with OS9 configuration sections in a deterministic way. -extends_documentation_fragment: -- dellemc_networking.os9.dellos9 - +extends_documentation_fragment: os9 options: lines: description: @@ -127,7 +126,7 @@ options: suboptions: filename: description: - - The filename to be used to store the backup configuration. If the filename + - The filename to be used to store the backup configuration. If the the filename is not given it will be generated based on the hostname, current time and date in format defined by _config.@ dir_path: @@ -140,21 +139,20 @@ options: and backup configuration will be copied in C(filename) within I(backup) directory. type: path type: dict + version_added: "2.8" notes: - This module requires Dell OS9 version 9.10.0.1P13 or above. - - This module requires to increase the ssh connection rate limit. Use the following command I(ip ssh connection-rate-limit 60) to configure the same. This can also be done with the - M(dellos9_config) module. -''' + M(os9_config) module. +""" EXAMPLES = """ -- dellos9_config: +- os9_config: lines: ['hostname {{ inventory_hostname }}'] provider: "{{ cli }}" - -- dellos9_config: +- os9_config: lines: - 10 permit ip host 1.1.1.1 any log - 20 permit ip host 2.2.2.2 any log @@ -164,8 +162,7 @@ EXAMPLES = """ parents: ['ip access-list extended test'] before: ['no ip access-list extended test'] match: exact - -- dellos9_config: +- os9_config: lines: - 10 permit ip host 1.1.1.1 any log - 20 permit ip host 2.2.2.2 any log @@ -174,8 +171,7 @@ EXAMPLES = """ parents: ['ip access-list extended test'] before: ['no ip access-list extended test'] replace: block - -- dellos9_config: +- os9_config: lines: ['hostname {{ inventory_hostname }}'] provider: "{{ cli }}" backup: yes @@ -205,13 +201,13 @@ backup_path: description: The full path to the backup file returned: when backup is yes type: str - sample: /playbooks/ansible/backup/dellos9_config.2016-07-16@22:28:34 + sample: /playbooks/ansible/backup/os9_config.2016-07-16@22:28:34 """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import get_config, get_sublevel_config -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import load_config, run_commands -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import WARNING_PROMPTS_RE +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import get_config, get_sublevel_config +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import os9_argument_spec, check_args +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import load_config, run_commands +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import WARNING_PROMPTS_RE from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, dumps @@ -264,7 +260,7 @@ def main(): backup_options=dict(type='dict', options=backup_spec) ) - argument_spec.update(dellos9_argument_spec) + argument_spec.update(os9_argument_spec) mutually_exclusive = [('lines', 'src'), ('parents', 'src')] @@ -343,4 +339,4 @@ def main(): if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/plugins/modules/dellos9_facts.py b/plugins/modules/os9_facts.py similarity index 96% rename from plugins/modules/dellos9_facts.py rename to plugins/modules/os9_facts.py index 98dea4c..8c4c01c 100644 --- a/plugins/modules/dellos9_facts.py +++ b/plugins/modules/os9_facts.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -# (c) 2015 Peter Sprygada, -# Copyright (c) 2016 Dell Inc. +# (c) 2020 Peter Sprygada, +# Copyright (c) 2020 Dell Inc. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function @@ -13,9 +13,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.1', 'supported_by': 'community'} -DOCUMENTATION = ''' +DOCUMENTATION = """ --- -module: dellos9_facts +module: os9_facts +version_added: "2.2" author: "Dhivya P (@dhivyap)" short_description: Collect facts from remote devices running Dell EMC Networking OS9 description: @@ -24,9 +25,7 @@ description: 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. -extends_documentation_fragment: -- dellemc_networking.os9.dellos9 - +extends_documentation_fragment: os9 options: gather_subset: description: @@ -39,24 +38,21 @@ options: default: [ '!config' ] notes: - This module requires OS9 version 9.10.0.1P13 or above. - - This module requires an increase of the SSH connection rate limit. Use the following command I(ip ssh connection-rate-limit 60) - to configure the same. This can be also be done with the M(dellos9_config) module. -''' + to configure the same. This can be also be done with the M(os9_config) module. +""" EXAMPLES = """ # Collect all facts from the device -- dellos9_facts: +- os9_facts: gather_subset: all - # Collect only the config and default facts -- dellos9_facts: +- os9_facts: gather_subset: - config - # Do not collect hardware facts -- dellos9_facts: +- os9_facts: gather_subset: - "!hardware" """ @@ -66,7 +62,6 @@ 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 @@ -88,7 +83,6 @@ ansible_net_image: description: The image file the device is running returned: always type: str - # hardware ansible_net_filesystems: description: All file system names available on the device @@ -102,13 +96,11 @@ ansible_net_memtotal_mb: description: The total memory on the remote device in Mb returned: when hardware is configured type: int - # config ansible_net_config: description: The current active config from the device returned: when config is configured type: str - # interfaces ansible_net_all_ipv4_addresses: description: All IPv4 addresses configured on the device @@ -134,8 +126,8 @@ except ImportError: izip = zip from ansible.module_utils.basic import AnsibleModule -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import run_commands -from ansible_collections.dellemc_networking.os9.plugins.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import run_commands +from ansible_collections.dellemc.os9.plugins.module_utils.network.os9 import os9_argument_spec, check_args from ansible.module_utils.six import iteritems @@ -511,7 +503,7 @@ def main(): gather_subset=dict(default=['!config'], type='list') ) - argument_spec.update(dellos9_argument_spec) + argument_spec.update(os9_argument_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) @@ -572,4 +564,4 @@ def main(): if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/plugins/terminal/dellos9.py b/plugins/terminal/os9.py similarity index 96% rename from plugins/terminal/dellos9.py rename to plugins/terminal/os9.py index ceb20f8..30b3019 100644 --- a/plugins/terminal/dellos9.py +++ b/plugins/terminal/os9.py @@ -1,7 +1,7 @@ # -# (c) 2016 Red Hat Inc. +# (c) 2020 Red Hat Inc. # -# Copyright (c) 2017 Dell Inc. +# Copyright (c) 2020 Dell Inc. # # This file is part of Ansible # @@ -80,4 +80,4 @@ class TerminalModule(TerminalBase): self._exec_cli_command(b'disable') elif prompt.endswith(b'#'): - self._exec_cli_command(b'disable') + self._exec_cli_command(b'disable') \ No newline at end of file diff --git a/roles/os9_aaa/LICENSE b/roles/os9_aaa/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_aaa/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_aaa/README.md b/roles/os9_aaa/README.md new file mode 100644 index 0000000..e0139be --- /dev/null +++ b/roles/os9_aaa/README.md @@ -0,0 +1,334 @@ +AAA role +======== + +This role facilitates the configuration of authentication authorization acccounting (AAA). It supports the configuration of TACACS for OS9. The AAA role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_aaa keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``radius_server`` | dictionary | Configures the radius server (see ``radius_server.*``) | os9 | +| ``radius_server.key`` | string (required): 0,7,LINE | Configures the authentication key for the radius server | os9 | +| ``radius_server.key_string`` | string | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only if *radius_server.key* is 7 or 0 | os9 | +| ``radius_server.retransmit`` | integer | Configures the number of retransmissions | os9 | +| ``radius_server.timeout`` | integer | Configures the timeout for retransmissions | os9 | +| ``radius_server.deadtime`` | integer | Configures the server dead time | os9 | +| ``radius_server.group`` | dictionary | Configures the radius servers group (see ``group.*``) | os9 | +| ``group.name`` | string (required) | Configures the group name of the radius servers | os9 | +| ``group.host`` | dictionary | Configures the radius server host in the group (see ``host.*``) | os9 | +| ``host.ip`` | string | Configures the radius server host address in the group | os9 | +| ``host.key`` | string (required): 0,7,LINE | Configures the authentication key | os9 | +| ``host.key_string`` | string: 7,0 | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only if *host.key* is 7 or 0 | os9 | +| ``host.retransmit`` | integer | Configures the number of retransmissions | os9 | +| ``host.auth_port`` | integer | Configures the authentication port (0 to 65535) | os9 | +| ``host.timeout`` | integer | Configures the timeout for retransmissions | os9 | +| ``host.state`` | string: present,absent | Removes the host from group of radius server if set to absent | os9 | +| ``group.vrf`` | dictionary | Configures the VRF for radius servers in the group (see ``vrf.*``) | os9 | +| ``vrf.vrf_name`` | string (required) | Configures the name of VRF for the radius server group | os9 | +| ``vrf.source_intf`` | integer | Configures the source interface for outgoing packets from servers in the group | os9 | +| ``vrf.state`` | string: present,absent | Removes the VRF from group of radius servers if set to absent | os9 | +| ``group.state`` | string: present,absent | Removes the radius server group if set to absent | os9 | +| ``radius_server.host`` | dictionary | Configures the radius server host (see ``host.*``) | os9 | +| ``host.ip`` | string | Configures the radius server host address | os9 | +| ``host.key`` | string (required); 0,7,LINE | Configures the authentication key | os9 | +| ``host.key_string`` | string | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only if *host.key* is 7 or 0 | os9 | +| ``host.retransmit`` | integer | Configures the number of retransmissions | os9 | +| ``host.auth_port`` | integer | Configures the authentication port (0 to 65535) | os9 | +| ``host.timeout`` | integer | Configures timeout for retransmissions | os9 | +| ``host.state`` | string: present,absent | Removes the radius server host if set to absent | os9 | +| ``auth.key`` | string (required); 0,7,LINE | Configures the authentication key | os9 | +| ``tacacs_server`` | dictionary | Configures the tacacs server (see ``tacacs_server.*``)| os9 | +| ``tacacs_server.key`` | string (required): 0,7,LINE | Configures the authentication key for tacacs server | os9 | +| ``tacacs_server.key_string`` | string | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only if *tacacs_server.key* is 7 or 0 | os9 | +| ``tacacs_server.group`` | dictionary | Configures the group of tacacs servers (see ``group.*``) | os9 | +| ``group.name`` | string (required) | Configures the group name of the tacacs servers | os9 | +| ``group.host`` | dictionary | Configures the tacacs server host in the group (see ``host.*``) | os9 | +| ``host.ip`` | string | Configures the tacacs server host address in the group | os9 | +| ``host.key`` | string (required): 0,7,LINE | Configures the authentication key of the tacacs server host | os9 | +| ``host.key_string`` | string | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only *host.key* is 7 or 0 | os9 | +| ``host.retransmit`` | integer | Configures the number of retransmissions | os9 | +| ``host.auth_port`` | integer | Configures the authentication port (0 to 65535) | os9 | +| ``host.timeout`` | integer | Configures timeout for retransmissions | os9 | +| ``host.state`` | string: present,absent | Removes the host from group of tacacs server if set to absent | os9 | +| ``group.vrf`` | dictionary | Configures VRF for tacacs servers in the group (see ``vrf.*``) | os9 | +| ``vrf.vrf_name`` | string (required) | Configures the name of VRF for tacacs server group | os9 | +| ``vrf.source_intf`` | integer | Configures source interface for outgoing packets from servers in the group | os9 | +| ``vrf.state`` | string: present,absent | Removes the VRF from group of tacacs server if set to absent | os9 | +| ``group.state`` | string: present,absent | Removes the tacacs server group if set to absent | os9 | +| ``tacacs_server.host`` | dictionary | Configures the tacacs server host (see ``host.*``) | os9 | +| ``host.ip`` | string | Configures the tacacs sever host address | os9 | +| ``host.key`` | string (required): 0,7,LINE | Configures the authentication key | os9 | +| ``host.key_string`` | string | Configures the user key string; variable takes the hidden user key string if value is 7; variable takes the unencrypted user key (clear-text) if value is 0; variable supported only if *host.key* is 7 or 0 | os9 | +| ``host.retransmit`` | integer | Configures the number of retransmissions | os9 | +| ``host.auth_port`` | integer | Configures the authentication port (0 to 65535) | os9 | +| ``host.timeout`` | integer | Configures the timeout for retransmissions | os9 | +| ``host.state`` | string: present,absent | Removes the tacacs server host if set to absent | os9 | +| ``aaa_accounting`` | dictionary | Configures accounting parameters (see ``aaa_accounting.*``) | os9 | +| ``aaa_accounting.commands`` | list | Configures accounting for exec (shell) and config commands (see ``commands.*``) | os9 | +| ``commands.enable_level`` | integer | Configures enable level for accounting of commands | os9 | +| ``commands.role_name`` | string | Configures user role for accounting of commands; variable is mutually exclusive with ``enable_level`` | os9 | +| ``commands.accounting_list_name`` | integer | Configures named accounting list for commands | os9 | +| ``commands.no_accounting`` | boolean | Configures no accounting of commands | os9 | +| ``commands.record_option`` | string: start-stop,stop-only,wait-start | Configures options to record data | os9 | +| ``commands.state`` | string: present,absent | Removes the named accounting list for the commands if set to absent | os9 | +| ``aaa_accounting.exec`` | list | Configures accounting for EXEC (shell) commands (see ``exec.*``) | os9 | +| ``exec.accounting_list_name`` | string | Configures named accounting list for exec commands | os9 | +| ``exec.no_accounting`` | boolean | Configures no accounting of EXEC commands | os9 | +| ``exec.record_option`` | string: start-stop,stop-only,wait-start | Configures options to record data | os9 | +| ``exec.state`` | string: present,absent | Removes the named accounting list for the exec commands if set to absent | os9 | +| ``aaa_accounting.suppress`` | boolean | Suppresses accounting for users with NULL username | os9| +| ``aaa_accounting.dot1x`` | string: none,start-stop,stop-only,wait-start | Configures accounting for dot1x events | os9 | +| ``aaa_accounting.rest`` | string:none,start-stop,stop-only,wait-start | Configures accounting for rest interface events | os9 | +| ``aaa_authorization`` | dictionary | Configures authorization parameters (see ``aaa_authorization.*``) | os9 | +| ``aaa_authorization.commands`` | list | Configures authorization for EXEC (shell) and config commands (see ``commands.*``)| os9 | +| ``commands.enable_level`` | integer | Configures enable level for authorization of commands | os9 | +| ``commands.role_name`` | string | Configures user role for authorization of commands; mutually exclusive with ``enable_level`` | os9 | +| ``commands.authorization_list_name`` | string | Configures named authorization list for commands | os9 | +| ``commands.authorization_method`` | string: none | Configures no authorization of commands | os9 | +| ``commands.use_data`` | string: local,tacacs+ | Configures data used for authorization | os9 | +| ``commands.state`` | string: present,absent | Removes the named authorization list for the commands if set to absent | os9 | +| ``aaa_authorization.config_commands`` | boolean | Configures authorization for configuration mode commands | os9 | +| ``aaa_authorization.role_only`` | boolean | Configures validation of authentication mode for user role | os9 | +| ``aaa_authorization.exec`` | list | Configures authorization for EXEC (shell) commands (see ``exec.*``) | os9 | +| ``exec.authorization_list_name`` | string | Configures named authorization list for EXEC commands | os9 | +| ``exec.authorization_method`` | string: none | Configures no authorization of EXEC commands | os9 | +| ``exec.use_data`` | string: local,tacacs+ | Configures data used for authorization | os9 | +| ``exec.state`` | string: present,absent | Removes the named authorization list for the EXEC commands if set to absent | os9 | +| ``aaa_authorization.network`` | string: none,radius,ias | Configures authorization for network events | os9 | +| ``aaa_authentication`` | dictionary | Configures authentication parameters (see ``aaa_authentication.*``) | os9 | +| ``aaa_radius`` | dictionary | Configures AAA for radius group of servers (see ``aaa_radius.*``) | os9 | +| ``aaa_radius.group`` | string | Configures name of the radius group of servers for AAA | os9 | +| ``aaa_radius.auth_method`` | string: pap,mschapv2 | Configures authentication method of radius group of servers for AAA | os9 | +| ``aaa_tacacs`` | dictionary | Configures AAA for tacacs group of servers (see ``aaa_tacacs.*``) | os9 | +| ``aaa_tacacs.group`` | string | Configures name of the tacacs group of servers for AAA | os9 | +| ``aaa_authentication.auth_list`` | list | Configures named authentication list for hosts (see ``host.*``) | os9 | +| ``auth_list.name`` | string | Configures named authentication list | os9 | +| ``auth_list.login_or_enable`` | string: enable,login | Configures authentication list for login or enable | os9 | +| ``auth_list.server`` | string: radius,tacacs+ | Configures AAA to use this list of all server hosts | os9 | +| ``auth_list.use_password`` | string: line,local,enable,none | Configures password to use for authentication | os9 | +| ``auth_list.state`` | string: present,absent | Removes the named authentication list if set to absent | os9 | +| ``aaa_authentication.dot1x`` | string: none,radius,ias | Configures authentication for dot1x events | os9 | +| ``line_terminal`` | dictionary | Configures the terminal line (see ``line_terminal.*``) | os9 | +| ``line_terminal.`` | dictionary | Configures the primary or virtual terminal line (see ``.*``); value can be console , vty | os9 | +| ``.authorization`` | dictionary | Configures authorization parameters of line terminal (see ``authorization.*``) | os9 | +| ``authorization.commands`` | list | Configures authorization for EXEC (shell) and config commands (see ``commands.*``) | os9 | +| ``commands.enable_level`` | integer | Configures enable level for authorization of commands at line terminal | os9 | +| ``commands.role_name`` | string | Configures user role for authorization of commands at line terminal; mutually exclusive with `enable_level` | os9 | +| ``commands.authorization_list_name`` | string | Configures named authorization list for commands | os9 | +| ``commands.state`` | string: present,absent | Removes the authorization of commands from line terminal if set to absent | os9 | +| ``authorization.exec`` | list | Configures authorization for EXEC (shell) commands at line terminal (see ``exec.*``) | os9 | +| ``exec.authorization_list_name`` | string | Configures named authorization list for EXEC commands | os9 | +| ``exec.state`` | string: present,absent | Removes the authorization of EXEC (shell) from line terminal if set to absent | os9 | +| ``.accounting`` | dictionary | Configures accounting parameters of line terminal (see ``accounting.*``) | os9 | +| ``accounting.commands`` | list | Configures accounting for EXEC (shell) and config commands (see ``commands.*``) | os9 | +| ``commands.enable_level`` | integer | Configures enable level for accounting of commands at line terminal | os9| +| ``commands.role_name`` | string | Configures user role for accounting of commands at line terminal; mutually exclusive with ``enable_level`` | os9 | +| ``commands.accounting_list_name`` | string | Configures named accounting list for commands | os9 | +| ``commands.state`` | string: present,absent | Removes the accounting of commands from line terminal if set to absent | os9| +| ``accounting.exec`` | list | Configures accounting for EXEC (shell) commands at line terminal (see ``exec.*``) | os9 | +| ``exec.accounting_list_name`` | string | Configures named accounting list for EXEC commands | os9 | +| ``exec.state`` | string: present,absent | Removes the accounting of EXEC (shell) from line terminal if set to absent | os9 | +| ``.authentication`` | dictionary | Configures authentication parameters of line terminal (see ``authentication.*``) | os9 | +| ``authentication.enable`` | string | Configures the authentication list for privilege-level password authentication | os9 | +| ``authentication.login`` | string | Configures the authentication list for password checking | os9 | +| ``client.ip`` | string | Configures the client ip for the radius server | os9 | +| ``client.key`` | string (required): 0,7,LINE | Configures the authentication key for the radius server | os9 | +> **NOTE**: Asterisk (*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_aaa* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_aaa* role to configure AAA for radius and TACACS servers. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with the corresponding Dell EMC Networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in the *build_dir* path. By default, it is set to false and it writes a simple playbook that only references the *os9_aaa* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_aaa: + radius_server: + key: radius + retransmit: 5 + timeout: 40 + deadtime: 2300 + group: + - name: RADIUS + host: + - ip: 2001:4898:f0:f09b::1002 + key: 0 + key_string: aaaa + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: test + source_intf: fortyGigE 1/2 + state: absent + state: present + host: + - ip: 2001:4898:f0:f09b::1002 + key: xxx + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + tacacs_server: + key: 7 + key_string: 9ea8ec421c2e2e5bec757f44205015f6d81e83a4f0aa52fa + group: + - name: TACACS + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aaa + retransmit: 6 + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: tes + source_intf: fortyGigE 1/3 + state: present + state: present + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aa + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + aaa_accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + record_option: start-stop + state: present + - role_name: netadmin + accounting_list_name: aa + no_accounting: none + suppress: True + exec: + - accounting_list_name: aaa + no_accounting: true + state: present + dot1x: none + rest: none + aaa_authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + use_data: local + state: present + - role_name: netadmin + authorization_list_name: aa + authorization_method: none + use_data: local + config_commands: True + role_only: + exec: + - authorization_list_name: aaa + authorization_method: if-authenticated + use_data: local + state: present + aaa_authentication: + auth_list: + - name: default + login_or_enable: login + server: radius + use_password: local + state: present + - name: console + server: tacacs+ + login_or_enable: login + use_password: local + aaa_radius: + group: RADIUS + auth_method: pap + aaa_tacacs: + group: TACACS + line_terminal: + vty 0: + authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + state: present + - role_name: netadmin + authorization_list_name: aa + state: present + exec: + - authorization_list_name: aa + state: present + accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + state: present + - role_name: netadmin + accounting_list_name: aa + state: absent + exec: + accounting_list_name: aa + state: present + authentication: + enable: + login: console + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_aaa + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_aaa/defaults/main.yml b/roles/os9_aaa/defaults/main.yml new file mode 100644 index 0000000..8fce003 --- /dev/null +++ b/roles/os9_aaa/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# defaults file for dellemc.os9.os9_aaa +attribute_type: + mandatory: mandatory + on_for_login_auth: on-for-login-auth + include_in_access_req: include-in-access-req + mac: "mac format" + mac_ietf: "mac format ietf" + mac_ietf_lower_case: "mac format ietf lower-case" + mac_ietf_upper_case: "mac format ietf upper-case" + mac_legacy: "mac format legacy" + mac_legacy_lower_case: "mac format legacy lower-case" + mac_legacy_upper_case: "mac format legacy upper-case" + mac_unformatted: "mac format unformatted" + mac_unformatted_lower_case: "mac format unformatted lower-case" + mac_unformatted_upper_case: "mac format unformatted upper-case" \ No newline at end of file diff --git a/roles/os9_aaa/handlers/main.yml b/roles/os9_aaa/handlers/main.yml new file mode 100644 index 0000000..ad771c4 --- /dev/null +++ b/roles/os9_aaa/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_aaa \ No newline at end of file diff --git a/roles/os9_aaa/meta/main.yml b/roles/os9_aaa/meta/main.yml new file mode 100644 index 0000000..650abac --- /dev/null +++ b/roles/os9_aaa/meta/main.yml @@ -0,0 +1,17 @@ +# copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_aaa role facilitates the configuration of Authentication Authorization Acccounting (AAA) attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 diff --git a/roles/os9_aaa/tasks/main.yml b/roles/os9_aaa/tasks/main.yml new file mode 100644 index 0000000..f6b43f6 --- /dev/null +++ b/roles/os9_aaa/tasks/main.yml @@ -0,0 +1,17 @@ +--- +# tasks file for os9 + + - name: "Generating AAA configuration for os9" + template: + src: os9_aaa.j2 + dest: "{{ build_dir }}/aaa9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning AAA configuration for os9" + os9_config: + src: os9_aaa.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_aaa/templates/os9_aaa.j2 b/roles/os9_aaa/templates/os9_aaa.j2 new file mode 100644 index 0000000..0d4aa9f --- /dev/null +++ b/roles/os9_aaa/templates/os9_aaa.j2 @@ -0,0 +1,680 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure AAA commands for os9 Devices +os9_aaa: + tacacs_server: + key: 7 + key_string: 9ea8ec421c2e2e5bec757f44205015f6d81e83a4f0aa52fa + group: + - name: TACACS + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aaa + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: test + source_intf: fortyGigE 1/2 + state: present + state: present + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aaa + auth_port: 3 + timeout: 2 + state: present + radius_server: + key: 7 + key_string: 9ea8ec421c2e2e5bec757f44205015f6d81e83a4f0aa52fb + retransmit: 5 + timeout: 10 + deadtime: 2000 + group: + - name: Radius + host: + - ip: 2001:4898:f0:f09b::1001 + key: 0 + key_string: aaa + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: test + source_intf: fortyGigE 1/3 + state: present + state: present + host: + - ip: 2001:4898:f0:f09b::1001 + key: 0 + key_string: aaa + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + aaa_accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + no_accounting: true + record_option: start-stop + state: present + suppress: True + exec: + - accounting_list_name: aaa + no_accounting: true + state: present + dot1x: none + rest: none + aaa_authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + use_data: local + state: present + - role_name: netadmin + authorization_list_name: aa + authorization_method: none + use_data: local + config_commands: True + role_only: True + exec: + - authorization_list_name: aaa + authorization_method: if-authenticated + use_data: local + state: present + aaa_radius: + group: RADIUS + auth_method: pap + aaa_tacacs: + group: TACACS + aaa_authentication: + auth_list: + - name: default + login_or_enable: login + server: tacacs+ + use_password: local + state: present + - name: console + server: radius + login_or_enable: login + use_password: local + line_terminal: + vty 0: + authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + state: present + - enable_level: 2 + authorization_list_name: aa + state: present + exec: + - authorization_list_name: aa + state: present + accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + state: present + - enable_level: 2 + accounting_list_name: aa + state: present + exec: + - accounting_list_name: aa + state: present + authentication: + enable: aa + login: console +##################################################} +{% if os9_aaa is defined and os9_aaa %} +{% for key in os9_aaa.keys() %} + {% set aaa_vars = os9_aaa[key] %} + {% if key == "tacacs_server" %} + {% set server = "tacacs-server" %} + {% endif %} + {% if key == "radius_server" %} + {% set server = "radius-server" %} + {% endif %} + {% if server is defined and server %} + {% if aaa_vars %} + {% set item = aaa_vars %} + {% if item.retransmit is defined %} + {% if item.retransmit %} +{{ server }} retransmit {{ item.retransmit }} + {% else %} +no {{ server }} retransmit + {% endif %} + {% endif %} + {% if item.timeout is defined %} + {% if item.timeout %} +{{ server }} timeout {{ item.timeout }} + {% else %} +no {{ server }} timeout + {% endif %} + {% endif %} + {% if item.deadtime is defined %} + {% if item.deadtime %} +{{ server }} deadtime {{ item.deadtime }} + {% else %} +no {{ server }} deadtime + {% endif %} + {% endif %} + {% if item.key is defined %} + {% if item.key == 0 or item.key == 7 %} + {% if item.key_string is defined and item.key_string%} +{{ server }} key {{ item.key }} {{ item.key_string }} + {% endif %} + {% elif item.key %} +{{ server }} key {{ item.key }} + {% else %} +no {{ server }} key + {% endif %} + {% endif %} + {% if item.host is defined and item.host %} + {% for hostlist in item.host %} + {% if hostlist.ip is defined and hostlist.ip %} + {% if hostlist.state is defined and hostlist.state == "absent" %} + {% if (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7) ) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) %} +no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +no {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} +no {{ server }} host {{ hostlist.ip }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7) )%} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) %} +no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} + {% else %} +no {{ server }} host {{ hostlist.ip }} + {% endif %} + {% else %} + {% if (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key== 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) %} +{{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} +{{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server"%} +{{ server }} host {{ hostlist.ip }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7))%} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) %} +{{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} + {% else %} +{{ server }} host {{ hostlist.ip }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if item.group is defined and item.group %} + {% for groupitem in item.group %} + {% if groupitem.name is defined and groupitem.name %} + {% if groupitem.state is defined and groupitem.state == "absent" %} +no {{ server }} group {{ groupitem.name }} + {% else %} +{{ server }} group {{ groupitem.name }} + {% if groupitem.host is defined and groupitem.host %} + {% for hostlist in groupitem.host %} + {% if hostlist.ip is defined and hostlist.ip %} + {% if hostlist.state is defined and hostlist.state == "absent" %} + {% if (hostlist.key is defined and (hostlist.key or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and (hostlist.key or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} + {% elif (hostlist.key is defined and (hostlist.key or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) %} + no {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + no {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + no {{ server }} host {{ hostlist.ip }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) %} + no {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} + {% else %} + no {{ server }} host {{ hostlist.ip }} + {% endif %} + {% else %} + {% if (hostlist.key is defined and (hostlist.key== 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) and (hostlist.timeout is defined and hostlist.timeout) %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} timeout {{ hostlist.timeout }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) and (hostlist.key_string is defined and hostlist.key_string) %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.key is defined and hostlist.key) and (hostlist.timeout is defined and hostlist.timeout) %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} timeout {{ hostlist.timeout }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) and (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) and (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server" %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.timeout is defined and hostlist.timeout) %} + {{ server }} host {{ hostlist.ip }} timeout {{ hostlist.timeout }} + {% elif (hostlist.auth_port is defined and hostlist.auth_port) %} + {% if server == "radius-server" %}{%set port = "auth-port" %}{%else %}{% set port = "port" %}{% endif %} + {{ server }} host {{ hostlist.ip }} {{ port }} {{ hostlist.auth_port }} + {% elif (hostlist.retransmit is defined and hostlist.retransmit) and server == "radius-server"%} + {{ server }} host {{ hostlist.ip }} retransmit {{ hostlist.retransmit }} + {% elif (hostlist.key is defined and (hostlist.key == 0 or hostlist.key == 7)) %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} {{ hostlist.key_string }} + {% elif (hostlist.key is defined and hostlist.key) %} + {{ server }} host {{ hostlist.ip }} key {{ hostlist.key }} + {% else %} + {{ server }} host {{ hostlist.ip }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if groupitem.vrf is defined and groupitem.vrf %} + {% if groupitem.vrf.vrf_name is defined and groupitem.vrf.vrf_name %} + {% if groupitem.vrf.state is defined and groupitem.vrf.state == "absent" %} + no {{ server }} vrf {{ groupitem.vrf.vrf_name }} + {% else %} + {% if groupitem.vrf.source_intf is defined and groupitem.vrf.source_intf %} + {{ server }} vrf {{ groupitem.vrf.vrf_name }} source-interface {{ groupitem.vrf.source_intf }} + {% else %} + {{ server }} vrf {{ groupitem.vrf.vrf_name }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} +{% endfor %} + + {% if os9_aaa.aaa_accounting is defined and os9_aaa.aaa_accounting %} + {% set aaa_accounting = os9_aaa.aaa_accounting %} + {% if aaa_accounting.suppress is defined %} + {% if aaa_accounting.suppress %} +aaa accounting suppress null-username + {% else %} +no aaa accounting suppress null-username + {% endif %} + {% endif %} + {% if aaa_accounting.dot1x is defined %} + {% if aaa_accounting.dot1x == "none" %} +aaa accounting dot1x default none + {% elif aaa_accounting.dotx %} +aaa accounting dot1x default {{ aaa_accounting.dot1x }} tacacs+ + {% else %} +no aaa accounting dotx default + {% endif %} + {% endif %} + {% if aaa_accounting.rest is defined %} + {% if aaa_accounting.rest == "none" %} +aaa accounting rest default none + {% elif aaa_accounting.rest %} +aaa accounting rest default {{ aaa_accounting.rest }} tacacs+ + {% else %} +no aaa accounting rest default + {% endif %} + {% endif %} + {% if aaa_accounting.exec is defined and aaa_accounting.exec %} + {% for command in aaa_accounting.exec %} + {% if command.accounting_list_name is defined and command.accounting_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa accounting exec {{ command.accounting_list_name }} + {% else %} + {% if command.record_option is defined and command.record_option %} +aaa accounting exec {{ command.accounting_list_name }} {{ command.record_option }} tacacs+ + {% elif command.no_accounting is defined and command.no_accounting %} +aaa accounting exec {{ command.accounting_list_name }} none + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if aaa_accounting.commands is defined and aaa_accounting.commands %} + {% for command in aaa_accounting.commands %} + {% if command.enable_level is defined and command.enable_level %} + {% if command.accounting_list_name is defined and command.accounting_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa accounting commands {{ command.enable_level }} {{ command.accounting_list_name }} + {% else %} + {% if command.record_option is defined and command.record_option %} +aaa accounting commands {{ command.enable_level }} {{ command.accounting_list_name }} {{ command.record_option }} tacacs+ + {% elif command.no_accounting is defined and command.no_accounting %} +aaa accounting commands {{ command.enable_level }} {{ command.accounting_list_name }} none + {% endif %} + {% endif %} + {% endif %} + {% elif command.role_name is defined and command.role_name %} + {% if command.accounting_list_name is defined and command.accounting_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa accounting commands role {{ command.role_name }} {{ command.accounting_list_name }} + {% else %} + {% if command.record_option is defined and command.record_option %} +aaa accounting commands role {{ command.role_name }} {{ command.accounting_list_name }} {{ command.record_option }} tacacs+ + {% elif command.no_accounting is defined and command.no_accounting %} +aaa accounting commands role {{ command.role_name }} {{ command.accounting_list_name }} none + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% if os9_aaa.aaa_authorization is defined and os9_aaa.aaa_authorization %} + {% set aaa_authorization = os9_aaa.aaa_authorization %} + {% if aaa_authorization.config_commands is defined %} + {% if aaa_authorization.config_commands %} +aaa authorization config-commands + {% else %} +no aaa authorization config-commands + {% endif %} + {% endif %} + {% if aaa_authorization.role_only is defined %} + {% if aaa_authorization.role_only %} +aaa authorization role-only + {% else %} +no aaa authorization role-only + {% endif %} + {% endif %} + {% if aaa_authorization.exec is defined and aaa_authorization.exec %} + {% for command in aaa_authorization.exec %} + {% if command.authorization_list_name is defined and command.authorization_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa authorization exec {{ command.authorization_list_name }} + {% else %} + {% if command.use_data is defined and command.use_data %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization exec {{ command.authorization_list_name }} {{ command.use_data }} {{ command.authorization_method }} + {% else %} +aaa authorization exec {{ command.authorization_list_name }} {{ command.use_data }} + {% endif %} + {% else %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization exec {{ command.authorization_list_name }} {{ command.authorization_method }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if aaa_authorization.commands is defined and aaa_authorization.commands %} + {% for command in aaa_authorization.commands %} + {% if command.enable_level is defined and command.enable_level %} + {% if command.authorization_list_name is defined and command.authorization_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa authorization commands {{ command.enable_level }} {{ command.authorization_list_name }} + {% else %} + {% if command.use_data is defined and command.use_data %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization commands {{ command.enable_level }} {{ command.authorization_list_name }} {{ command.use_data }} {{ command.authorization_method }} + {% else %} +aaa authorization commands {{ command.enable_level }} {{ command.authorization_list_name }} {{ command.use_data }} + {% endif %} + {% else %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization commands {{ command.enable_level }} {{ command.authorization_list_name }} {{ command.authorization_method }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% elif command.role_name is defined and command.role_name %} + {% if command.authorization_list_name is defined and command.authorization_list_name %} + {% if command.state is defined and command.state == "absent" %} +no aaa authorization commands role {{ command.role_name }} {{ command.authorization_list_name }} + {% else %} + {% if command.use_data is defined and command.use_data %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization commands role {{ command.role_name }} {{ command.authorization_list_name }} {{ command.use_data }} {{ command.authorization_method }} + {% else %} +aaa authorization commands role {{ command.role_name }} {{ command.authorization_list_name }} {{ command.use_data }} + {% endif %} + {% else %} + {% if command.authorization_method is defined and command.authorization_method %} +aaa authorization commands role {{ command.role_name }} {{ command.authorization_list_name }} {{ command.authorization_method }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + + {% if os9_aaa.aaa_radius is defined and os9_aaa.aaa_radius %} + {% if os9_aaa.aaa_radius.group is defined %} + {% if os9_aaa.aaa_radius.group %} +aaa radius group {{ os9_aaa.aaa_radius.group }} + {% else %} +no aaa radius group + {% endif %} + {% endif %} + {% if os9_aaa.aaa_radius.auth_method is defined %} + {% if os9_aaa.aaa_radius.auth_method %} +aaa radius auth-method {{ os9_aaa.aaa_radius.auth_method }} + {% else %} +no aaa radius auth-method + {% endif %} + {% endif %} + {% endif %} + {% if os9_aaa.aaa_tacacs is defined and os9_aaa.aaa_tacacs %} + {% if os9_aaa.aaa_tacacs.group is defined %} + {% if os9_aaa.aaa_tacacs.group %} +aaa tacacs group {{ os9_aaa.aaa_tacacs.group }} + {% else %} +no aaa tacacs group + {% endif %} + {% endif %} + {% endif %} + + {% if os9_aaa.aaa_authentication is defined and os9_aaa.aaa_authentication %} + {% if os9_aaa.aaa_authentication.auth_list is defined and os9_aaa.aaa_authentication.auth_list %} + {% for auth_list in os9_aaa.aaa_authentication.auth_list %} + {% if auth_list.login_or_enable is defined and auth_list.login_or_enable %} + {% if auth_list.name is defined and auth_list.name %} + {% if auth_list.state is defined and auth_list.state == "absent" %} +no aaa authentication {{ auth_list.login_or_enable }} {{ auth_list.name }} + {% else %} + {% if auth_list.server is defined and auth_list.server %} + {% if auth_list.use_password is defined and auth_list.use_password %} +aaa authentication {{ auth_list.login_or_enable }} {{ auth_list.name }} {{ auth_list.server }} {{ auth_list.use_password }} + {% else %} +aaa authentication {{ auth_list.login_or_enable }} {{ auth_list.name }} {{ auth_list.server }} + {% endif %} + {% else %} + {% if auth_list.use_password is defined and auth_list.use_password %} +aaa authentication {{ auth_list.login_or_enable }} {{ auth_list.name }} {{ auth_list.use_password }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + + {% if os9_aaa.line_terminal is defined and os9_aaa.line_terminal %} + {% for terminal in os9_aaa.line_terminal.keys() %} + {% set terminal_vars = os9_aaa.line_terminal[terminal] %} +line {{ terminal }} + {% if terminal_vars.authorization is defined and terminal_vars.authorization %} + {% if terminal_vars.authorization.commands is defined and terminal_vars.authorization.commands %} + {% for commands in terminal_vars.authorization.commands %} + {% if commands.enable_level is defined and commands.enable_level %} + {% if commands.state is defined and commands.state == "absent" %} + no authorization commands {{ commands.enable_level }} + {% else %} + {% if commands.authorization_list_name is defined and commands.authorization_list_name %} + authorization commands {{ commands.enable_level }} {{ commands.authorization_list_name }} + {% endif %} + {% endif %} + {% elif commands.role_name is defined and commands.role_name %} + {% if commands.state is defined and commands.state == "absent" %} + no authorization commands role {{ commands.role_name }} + {% else %} + {% if commands.authorization_list_name is defined and commands.authorization_list_name %} + authorization commands role {{ commands.role_name }} {{ commands.authorization_list_name }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if terminal_vars.authorization.exec is defined and terminal_vars.authorization.exec %} + {% set exec = terminal_vars.authorization.exec %} + {% if exec.state is defined and exec.state == "absent" %} + no authorization exec + {% else %} + {% if exec.authorization_list_name is defined and exec.authorization_list_name %} + authorization exec {{ exec.authorization_list_name }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if terminal_vars.accounting is defined and terminal_vars.accounting %} + {% if terminal_vars.accounting.commands is defined and terminal_vars.accounting.commands %} + {% for commands in terminal_vars.accounting.commands %} + {% if commands.enable_level is defined and commands.enable_level %} + {% if commands.state is defined and commands.state == "absent" %} + no accounting commands {{ commands.enable_level }} + {% else %} + {% if commands.accounting_list_name is defined and commands.accounting_list_name %} + accounting commands {{ commands.enable_level }} {{ commands.accounting_list_name }} + {% endif %} + {% endif %} + {% elif commands.role_name is defined and commands.role_name %} + {% if commands.state is defined and commands.state == "absent" %} + no accounting commands role {{ commands.role_name }} + {% else %} + {% if commands.accounting_list_name is defined and commands.accounting_list_name %} + accounting commands role {{ commands.role_name }} {{ commands.accounting_list_name }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if terminal_vars.accounting.exec is defined and terminal_vars.accounting.exec %} + {% set exec = terminal_vars.accounting.exec %} + {% if exec.state is defined and exec.state == "absent" %} + no accounting exec + {% else %} + {% if exec.accounting_list_name is defined and exec.accounting_list_name %} + authorization exec {{ exec.accounting_list_name }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if terminal_vars.authentication is defined and terminal_vars.authentication %} + {% if terminal_vars.authentication.enable is defined %} + {% if terminal_vars.authentication.enable %} + enable authentication {{ terminal_vars.authentication.enable }} + {% else %} + no enable authentication + {% endif %} + {% endif %} + {% if terminal_vars.authentication.login is defined %} + {% if terminal_vars.authentication.login %} + login authentication {{ terminal_vars.authentication.login }} + {% else %} + no login authentication + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_aaa/tests/inventory.yaml b/roles/os9_aaa/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_aaa/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_aaa/tests/main.os6.yaml b/roles/os9_aaa/tests/main.os6.yaml new file mode 100644 index 0000000..b4e871b --- /dev/null +++ b/roles/os9_aaa/tests/main.os6.yaml @@ -0,0 +1,133 @@ +--- +# vars file for dellemc.os9.os9_aaa, +# below gives a sample configuration +# Sample variables for OS9 device +os9_aaa: + radius_server: + key: radius + retransmit: 5 + timeout: 40 + deadtime: 2300 + group: + - name: RADIUS + host: + - ip: 2001:4898:f0:f09b::1002 + key: 0 + key_string: aaaa + retransmit: 5 + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: test + source_intf: fortyGigE 1/2 + state: absent + state: present + host: + - ip: 10.1.1.1 + key: 0 + key_string: aaa + retransmit: 6 + auth_port: 3 + timeout: 2 + state: present + tacacs_server: + key: 7 + key_string: 9ea8ec421c2e2e5bec757f44205015f6d81e83a4f0aa52fa + group: + - name: TACACS + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aaa + auth_port: 3 + timeout: 2 + state: present + vrf: + vrf_name: tes + source_intf: fortyGigE 1/3 + state: present + state: present + host: + - ip: 2001:4898:f0:f09b::1000 + key: 0 + key_string: aaa + auth_port: 3 + timeout: 2 + state: present + aaa_accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + record_option: start-stop + state: present + - role_name: netadmin + accounting_list_name: aa + no_accounting: none + suppress: True + exec: + - accounting_list_name: aaa + no_accounting: true + state: present + dot1x: none + rest: none + aaa_authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + use_data: local + state: present + - role_name: netadmin + authorization_list_name: aa + authorization_method: none + use_data: local + config_commands: True + role_only: + exec: + - authorization_list_name: aaa + authorization_method: if-authenticated + use_data: local + state: present + line_terminal: + vty 0: + authorization: + commands: + - enable_level: 2 + authorization_list_name: aa + state: present + - role_name: netadmin + authorization_list_name: aa + state: present + exec: + - authorization_list_name: aa + state: present + accounting: + commands: + - enable_level: 2 + accounting_list_name: aa + state: present + - role_name: netadmin + accounting_list_name: aa + state: absent + exec: + accounting_list_name: aa + state: present + authentication: + enable: + login: console + aaa_radius: + group: RADIUS + auth_method: pap + aaa_tacacs: + group: TACACS + aaa_authentication: + auth_list: + - name: default + login_or_enable: login + server: tacacs+ + use_password: local + state: present + - name: console + server: radius + login_or_enable: login + use_password: local \ No newline at end of file diff --git a/roles/os9_aaa/tests/test.yaml b/roles/os9_aaa/tests/test.yaml new file mode 100644 index 0000000..e99880c --- /dev/null +++ b/roles/os9_aaa/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_aaa \ No newline at end of file diff --git a/roles/os9_aaa/vars/main.yml b/roles/os9_aaa/vars/main.yml new file mode 100644 index 0000000..e198e3e --- /dev/null +++ b/roles/os9_aaa/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_aaa \ No newline at end of file diff --git a/roles/os9_acl/LICENSE b/roles/os9_acl/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_acl/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_acl/README.md b/roles/os9_acl/README.md new file mode 100644 index 0000000..a744e55 --- /dev/null +++ b/roles/os9_acl/README.md @@ -0,0 +1,139 @@ +ACL role +======== + +This role facilitates the configuration of an access-control list (ACL). It supports the configuration of different types of ACLs (standard and extended) for both IPv4 and IPv6, and assigns the access-class to the line terminals. + +The ACL role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_acl keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``type`` | string (required): ipv4, ipv6, mac | Configures the L3 (IPv4/IPv6) or L2 (MAC) access-control list | os9 | +| ``name`` | string (required) | Configures the name of the access-control list | os9 | +| ``description`` | string | Configures the description about the access-control list | os9 | +| ``remark`` | list | Configures the ACL remark (see ``remark.*``) | os9 | +| ``remark.number`` | integer (required) | Configures the remark sequence number | os9 | +| ``remark.description`` | string | Configures the remark description | os9 | +| ``remark.state`` | string: absent,present\* | Deletes the configured remark for an ACL entry if set to absent | os9 | +| ``extended`` | boolean: true,false | Configures an extended ACL type if set to true; configures a standard ACL if set to false | os9 | +| ``entries`` | list | Configures ACL rules (see ``seqlist.*``) | os9 | +| ``entries.number`` | integer (required) | Specifies the sequence number of the ACL rule | os9 | +| ``entries.permit`` | boolean (required): true,false | Specifies the rule to permit packets if set to true; specifies to reject packets if set to false | os9 | +| ``entries.protocol`` | string (required) | Specifies the type of protocol or the protocol number to filter | os9 | +| ``entries.source`` | string (required) | Specifies the source address to match in the packets | os9 | +| ``entries.src_condition`` | string | Specifies the condition to filter packets from the source address; ignored if MAC | os9 | +| ``entries.destination`` | string (required) | Specifies the destination address to match in the packets | os9 | +| ``entries.dest_condition`` | string | Specifies the condition to filter packets to the destination address | os9 | +| ``entries.other_options`` | string | Specifies the other options applied on packets (count, log, order, monitor, and so on) | os9 | +| ``entries.state`` | string: absent,present\* | Deletes the rule from the ACL if set to absent | os9 | +| ``stage_ingress`` | list | Configures ingress ACL to the interface (see ``stage_ingress.*``) | os9 | +| ``stage_ingress.name`` | string (required) | Configures the ingress ACL filter to the interface with this interface name | os9 | +| ``stage_ingress.state`` | string: absent,present\* | Deletes the configured ACL from the interface if set to absent | os9 | +| ``stage_ingress.seq_number`` | integer | Configure the sequence number (greater than 0) to rank precedence for this interface and direction | +| ``stage_egress`` | list | Configures egress ACL to the interface (see ``stage_egress.*``) | os9 | +| ``stage_egress.name`` | string (required) | Configures the egress ACL filter to the interface with this interface name | os9 | +| ``stage_egress.state`` | string: absent,present\* | Deletes the configured egress ACL from the interface if set to absent | os9 | +| ``lineterminal`` | list | Configures the terminal to apply the ACL (see ``lineterminal.*``) | os9 | +| ``lineterminal.line`` | string (required) | Configures access-class on the line terminal | os9 | +| ``lineterminal.state`` | string: absent,present\* | Deletes the access-class from line terminal if set to absent | os9 | +| ``state`` | string: absent,present\* | Deletes the ACL if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-------------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes /os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (_*_) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_acl* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_acl* role to configure different types of ACLs (standard and extended) for both IPv4 and IPv6 and assigns the access-class to the line terminals. The example creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with the corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, it generates the configuration commands as a .part file in the *build_dir* path. By default it is set to false. It writes a simple playbook that only references the *os9_acl* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_acl: + - type: ipv4 + name: ssh-only + description: ipv4acl + extended: true + remark: + - number: 5 + description: "ipv4remark" + entries: + - number: 5 + permit: true + protocol: tcp + source: any + src_condition: ack + destination: any + dest_condition: eq 22 + other_options: count + state: present + stage_ingress: + - name: fortyGigE 1/28 + state: present + stage_egress: + - name: fortyGigE 1/28 + state: present + lineterminal: + - line: vty 1 + state: present + - line: vty 2 + state: absent + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_acl + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_acl/defaults/main.yml b/roles/os9_acl/defaults/main.yml new file mode 100644 index 0000000..7c19601 --- /dev/null +++ b/roles/os9_acl/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_acl \ No newline at end of file diff --git a/roles/os9_acl/handlers/main.yml b/roles/os9_acl/handlers/main.yml new file mode 100644 index 0000000..ad771c4 --- /dev/null +++ b/roles/os9_acl/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_aaa \ No newline at end of file diff --git a/roles/os9_acl/meta/main.yml b/roles/os9_acl/meta/main.yml new file mode 100644 index 0000000..56ea045 --- /dev/null +++ b/roles/os9_acl/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_acl role facilitates the configuration of access control list (ACL) attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 + diff --git a/roles/os9_acl/tasks/main.yml b/roles/os9_acl/tasks/main.yml new file mode 100644 index 0000000..6132f79 --- /dev/null +++ b/roles/os9_acl/tasks/main.yml @@ -0,0 +1,16 @@ +--- +#tasks file for os9 + - name: "Generating ACL configuration for os9" + template: + src: os9_acl.j2 + dest: "{{ build_dir }}/acl9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning ACL configuration for os9" + os9_config: + src: os9_acl.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_acl/templates/os9_acl.j2 b/roles/os9_acl/templates/os9_acl.j2 new file mode 100644 index 0000000..b47a1c2 --- /dev/null +++ b/roles/os9_acl/templates/os9_acl.j2 @@ -0,0 +1,277 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{#################################### + +Purpose: +Configure ACL commands for os9 devices + +os9_acl: + - name: ssh-only + type: ipv4 + description: acl + extended: true + remark: + - number: 1 + description: helloworld + state: present + entries: + - number: 10 + permit: true + protocol: tcp + source: any + destination: any + src_condition: eq 22 + dest_condition: ack + other_options: count + state: present + stage_ingress: + - name: fortyGigE 1/8 + state: present + - name: fortyGigE 1/9 + state: present + stage_egress: + - name: fortyGigE 1/19 + state: present + lineterminal: + - line: vty 0 + state: present + - line: vty 1 + state: present + state: present + - name: ipv6-ssh-only + type: ipv6 + entries: + - number: 10 + permit: true + protocol: ipv6 + source: 2001:4898::/32 + destination: any + - number: 20 + permit: true + protocol: tcp + source: any + src_condition: ack + destination: any + - number: 40 + permit: true + protocol: tcp + source: any + destination: any + state: present + lineterminal: + - line: vty 0 + state: present + - line: vty 1 + state: present +#####################################} +{% if os9_acl is defined and os9_acl %} + {% for val in os9_acl + %} + {% if val.name is defined and val.name %} + {% if val.state is defined and val.state == "absent" %} + {% if val.type is defined and val.type == "ipv4" %} + {% if val.extended is defined and val.extended %} +no ip access-list extended {{ val.name }} + {% else %} +no ip access-list standard {{ val.name }} + {% endif %} + {% elif val.type is defined and val.type == "ipv6" %} +no ipv6 access-list {{ val.name }} + {% elif val.type is defined and val.type == "mac" %} + {% if val.extended is defined and val.extended %} +no mac access-list extended {{ val.name }} + {% else %} +no mac access-list standard {{ val.name }} + {% endif %} + {% endif %} + {% else %} + {% if val.type is defined and val.type == "ipv4" %} + {% if val.extended is defined and val.extended %} +ip access-list extended {{ val.name }} + {% else %} +ip access-list standard {{ val.name }} + {% endif %} + {% elif val.type is defined and val.type == "ipv6" %} +ipv6 access-list {{ val.name }} + {% elif val.type is defined and val.type == "mac" %} + {% if val.extended is defined and val.extended %} +mac access-list extended {{ val.name }} + {% else %} +mac access-list standard {{ val.name }} + {% endif %} + {% endif %} + {% if val.description is defined %} + {% if val.description %} + description {{ val.description }} + {% else %} + no description a + {% endif %} + {% endif %} + {% if val.remark is defined and val.remark %} + {% for remark in val.remark %} + {% if remark.number is defined and remark.number %} + {% if remark.state is defined and remark.state == "absent" %} + no remark {{ remark.number }} + {% else %} + {% if remark.description is defined and remark.description %} + remark {{ remark.number }} {{ remark.description }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if val.entries is defined and val.entries %} + {% for rule in val.entries %} + {% if rule.number is defined and rule.number %} + {% if rule.state is defined and rule.state == "absent" %} + no seq {{ rule.number }} + {% else %} + {% if rule.permit is defined %} + {% if rule.permit %} + {% set is_permit = "permit" %} + {% else %} + {% set is_permit = "deny" %} + {% endif %} + {% if val.type is defined and val.type == "mac" %} + {% if rule.source is defined and rule.source %} + {% if rule.destination is defined and rule.destination %} + {% if rule.other_options is defined and rule.other_options %} + {% if rule.other_options == "log" %} + {% set other_options = rule.other_options + ' threshold-in-msgs 10 interval 5' %} + {% else %} + {% set other_options = rule.other_options %} + {% endif %} + seq {{ rule.number }} {{ is_permit }} {{ rule.source }} {{ rule.destination }} {{ other_options }} + {% else %} + seq {{ rule.number }} {{ is_permit }} {{ rule.source }} {{ rule.destination }} + {% endif %} + {% endif %} + {% endif %} + {% else %} + {% if rule.protocol is defined and rule.protocol %} + {% if rule.source is defined and rule.source %} + {% if rule.destination is defined and rule.destination %} + {% if rule.src_condition is defined and rule.src_condition %} + {% if rule.dest_condition is defined and rule.dest_condition %} + {% if rule.other_options is defined and rule.other_options %} + {% if rule.other_options == "log" %} + {% set other_options = rule.other_options + ' threshold-in-msgs 10 interval 5' %} + {% else %} + {% set other_options = rule.other_options %} + {% endif %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.src_condition }} {{ rule.destination }} {{ rule.dest_condition }} {{ other_options }} + {% else %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.src_condition }} {{ rule.destination }} {{ rule.dest_condition }} + {% endif %} + {% else %} + {% if rule.other_options is defined and rule.other_options %} + {% if rule.other_options == "log" %} + {% set other_options = rule.other_options + ' threshold-in-msgs 10 interval 5' %} + {% else %} + {% set other_options = rule.other_options %} + {% endif %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.src_condition }} {{ rule.destination }} {{ other_options }} + {% else %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.src_condition }} {{ rule.destination }} + {% endif %} + {% endif %} + {% else %} + {% if rule.dest_condition is defined and rule.dest_condition %} + {% if rule.other_options is defined and rule.other_options %} + {% if rule.other_options == "log" %} + {% set other_options = rule.other_options + ' threshold-in-msgs 10 interval 5' %} + {% else %} + {% set other_options = rule.other_options %} + {% endif %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }} {{ rule.dest_condition }} {{ other_options }} + {% else %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }} {{ rule.dest_condition }} + {% endif %} + {% else %} + {% if rule.other_options is defined and rule.other_options %} + {% if rule.other_options == "log" %} + {% set other_options = rule.other_options + ' threshold-in-msgs 10 interval 5' %} + {% else %} + {% set other_options = rule.other_options %} + {% endif %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }} {{ other_options }} + {% else %} + seq {{ rule.number }} {{ is_permit }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if val.lineterminal is defined and val.lineterminal %} + {% if val.type is defined and not val.type == "mac" %} + {% for vty in val.lineterminal %} + {% if vty.line is defined and vty.line %} +line {{ vty.line }} + {% if vty.state is defined and vty.state == "absent" %} + no access-class {{ val.name }} {{ val.type }} + {% else %} + access-class {{ val.name }} {{ val.type }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + + {% if val.stage_ingress is defined and val.stage_ingress %} + {% for intf in val.stage_ingress %} + {% if intf.state is defined and intf.state == "absent" %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if val.type is defined and val.type == "mac" %} + no mac access-group {{ val.name }} in + {% else %} + no ip access-group {{ val.name }} in + {% endif %} + {% endif %} + {% else %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if val.type is defined and val.type == "mac" %} + mac access-group {{ val.name }} in + {% else %} + ip access-group {{ val.name }} in + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if val.stage_egress is defined and val.stage_egress %} + {% for intf in val.stage_egress %} + {% if intf.state is defined and intf.state == "absent" %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if val.type is defined and val.type == "mac" %} + no mac access-group {{ val.name }} out + {% else %} + no ip access-group {{ val.name }} out + {% endif %} + {% endif %} + {% else %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if val.type is defined and val.type == "mac" %} + mac access-group {{ val.name }} out + {% else %} + ip access-group {{ val.name }} out + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_acl/tests/inventory.yaml b/roles/os9_acl/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_acl/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_acl/tests/main.os9.yaml b/roles/os9_acl/tests/main.os9.yaml new file mode 100644 index 0000000..9f083bb --- /dev/null +++ b/roles/os9_acl/tests/main.os9.yaml @@ -0,0 +1,88 @@ +--- +# vars file for dellemc.os9.os9_acl, +# below gives a sample configuration +# Sample variables for OS9 device +os9_acl: + - name: ssh-only-mac + type: mac + description: macacl + extended: true + remark: + - number: 1 + description: mac + state: present + entries: + - number: 5 + permit: true + protocol: tcp + source: any + destination: any + dest_condition: eq 2 + other_options: count + state: present + - number: 6 + permit: false + protocol: tcp + source: bb:bb:bb:bb:bb:bb ff:ff:ff:ff:ff:ff + destination: any + dest_condition: log + state: present + stage_ingress: + - name: fortyGigE 1/28 + state: present + - name: fortyGigE 1/27 + state: present + stage_egress: + - name: fortyGigE 1/28 + state: present + lineterminal: + - line: vty 1 + state: present + - line: vty 2 + state: absent + - line: vty 3 + state: present + - name: ipv6-ssh-only + type: ipv6 + description: ipv6acl + remark: + - number: 1 + description: ipv6 + entries: + - number: 10 + permit: true + protocol: ipv6 + source: 2001:4898::/32 + destination: any + - number: 20 + permit: true + protocol: tcp + source: any + src_condition: eq 2 + destination: 2404:f801::/32 + - number: 30 + permit: true + protocol: tcp + source: any + destination: 2a01:110::/31 + dest_condition: ack + - number: 40 + permit: true + protocol: tcp + source: any + destination: any + stage_ingress: + - name: fortyGigE 1/26 + state: present + - name: fortyGigE 1/27 + state: present + stage_egress: + - name: fortyGigE 1/26 + state: present + lineterminal: + - line: vty 0 + state: absent + - line: vty 1 + - line: vty 2 + - line: vty 3 + state: present \ No newline at end of file diff --git a/roles/os9_acl/tests/test.yaml b/roles/os9_acl/tests/test.yaml new file mode 100644 index 0000000..dbe56bc --- /dev/null +++ b/roles/os9_acl/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_acl \ No newline at end of file diff --git a/roles/os9_acl/vars/main.yml b/roles/os9_acl/vars/main.yml new file mode 100644 index 0000000..95a3936 --- /dev/null +++ b/roles/os9_acl/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_acl \ No newline at end of file diff --git a/roles/os9_bgp/LICENSE b/roles/os9_bgp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_bgp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_bgp/README.md b/roles/os9_bgp/README.md new file mode 100644 index 0000000..ec28861 --- /dev/null +++ b/roles/os9_bgp/README.md @@ -0,0 +1,229 @@ +BGP role +======== + +This role facilitates the configuration of border gateway protocol (BGP) attributes. It supports the configuration of router ID, networks, neighbors, and maximum path. This role is abstracted for Dell EMC platforms running OS9. + +The BGP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 vas a value +- If variable *os9_cfg_generate* is set to true, it generates the role configuration commands in a file +- Any role variable with a corresponding state variable setting to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_bgp keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``asn`` | string (required) | Configures the autonomous system (AS) number of the local BGP instance | os9 | +| ``router_id`` | string | Configures the IP address of the local BGP router instance | os9 | +| ``graceful_restart`` | boolean | Configures graceful restart capability | os9 | +| ``graceful_restart.state`` | string: absent,present\* | Removes graceful restart capability if set to absent | os9 | +| ``maxpath_ibgp`` | integer | qqConfigures the maximum number of paths to forward packets through iBGP (1 to 64; default 1) | os9 | +| ``maxpath_ebgp`` | integer | Configures the maximum number of paths to forward packets through eBGP (1 to 64; default 1) | os9 | +| ``best_path`` | list | Configures the default best-path selection (see ``best_path.*``) | os9 | +| ``best_path.as_path`` | string (required): ignore,multipath-relax | Configures the AS path used for the best-path computation | os9 | +| ``best_path.as_path_state`` | string: absent,present\* | Deletes the AS path configuration if set to absent | os9 | +| ``best_path.ignore_router_id`` | boolean: true,false | Ignores the router identifier in best-path computation if set to true | os9 | +| ``best_path.med`` | list | Configures the MED attribute (see ``med.*``) | os9 | +| ``med.attribute`` | string (required): confed,missing-as-best | Configures the MED attribute used for the best-path computation | os9 | +| ``med.state`` | string: absent,present\* | Deletes the MED attribute if set to absent | os9, | +| ``ipv4_network`` | list | Configures an IPv4 BGP networks (see ``ipv4_network.*``) | , os9, | +| ``ipv4_network.address`` | string (required) | Configures the IPv4 address of the BGP network (A.B.C.D/E format) | os9 | +| ``ipv4_network.state`` | string: absent,present\* | Deletes an IPv4 BGP network if set to absent | os9 | +| ``ipv6_network`` | list | Configures an IPv6 BGP network (see ``ipv6_network.*``) | os9 | +| ``ipv6_network.address`` | string (required) | Configures the IPv6 address of the BGP network (2001:4898:5808:ffa2::1/126 format) | os9 | +| ``ipv6_network.state`` | string: absent,present\* | Deletes an IPv6 BGP network if set to absent | os9 | +| ``neighbor`` | list | Configures IPv4 BGP neighbors (see ``neighbor.*``) | os9 | +| ``neighbor.ip`` | string (required) | Configures the IPv4 address of the BGP neighbor (10.1.1.1) | os9 | +| ``neighbor.interface`` | string | Configures the BGP neighbor interface details | | +| ``neighbor.name`` | string (required) | Configures the BGP peer-group with this name; supported only when the neighbor is a peer group; mutually exclusive with *neighbor.ip* | os9 | +| ``neighbor.type`` | string (required): ipv4,ipv6,peergroup | Specifies the BGP neighbor type | os9 | +| ``neighbor.remote_asn`` | string (required) | Configures the remote AS number of the BGP neighbor | os9 | +| ``neighbor.remote_asn_state`` | string: absent,present\* | Deletes the remote AS number from the peer group if set to absent; supported only when *neighbor.type* is "peergroup" | os9 | +| ``neighbor.timer`` | string | Configures neighbor timers ( ); 5 10, where 5 is the keepalive interval and 10 is the holdtime | os9 | +| ``neighbor.default_originate`` | boolean: true, false\* | Configures default originate routes to the BGP neighbor | os9 | +| ``neighbor.peergroup`` | string | Configures neighbor to BGP peer-group (configured peer-group name) | os9 | +| ``neighbor.peergroup_state`` | string: absent,present\* | Deletes the IPv4 BGP neighbor from the peer-group if set to absent | os9 | +| ``neighbor.distribute_list`` | list | Configures the distribute list to filter networks from routing updates (see ``distribute_list.*``) | os9 | +| ``distribute_list.in`` | string | Configures the name of the prefix-list to filter incoming packets | os9 | +| ``distribute_list.in_state`` | string: absent,present\* | Deletes the filter at incoming packets if set to absent | os9 | +| ``distribute_list.out`` | string | Configures the name of the prefix-list to filter outgoing packets | os9 | +| ``distribute_list.out_state`` | string: absent,present\* | Deletes the filter at outgoing packets if set to absent | os9 | +| ``neighbor.admin`` | string: up,down | Configures the administrative state of the neighbor | os9 | +| ``neighbor.adv_interval`` | integer | Configures the advertisement interval of the neighbor | os9 | +| ``neighbor.fall_over`` | string: absent,present | Configures the session fall on peer-route loss | os9 | +| ``neighbor.sender_loop_detect`` | boolean: true,false | Enables/disables the sender-side loop detect for neighbors | os9 | +| ``neighbor.src_loopback`` | integer | Configures the source loopback interface for routing packets | os9 | +| ``neighbor.src_loopback_state`` | string: absent,present\* | Deletes the source for routing packets if set to absent | os9 | +| ``neighbor.ebgp_multihop`` | integer | Configures the maximum-hop count value allowed in eBGP neighbors that are not directly connected (default 255) | os9 | +| ``neighbor.passive`` | boolean: true,false\* | Configures the passive BGP peer group; supported only when neighbor is a peer-group | os9 | +| ``neighbor.subnet`` | string (required) | Configures the passive BGP neighbor to this subnet; required together with the *neighbor.passive* key for os9 devices | , os9, | +| ``neighbor.subnet_state`` | string: absent,present\* | Deletes the subnet range set for dynamic IPv4 BGP neighbor if set to absent | os9 | +| ``neighbor.limit`` | integer | Configures maximum dynamic peers count (key is required together with ``neighbor.subnet``) | | +| ``neighbor.bfd`` | boolean | Enables BDF for neighbor | | +| ``neighbor.state`` | string: absent,present\* | Deletes the IPv4 BGP neighbor if set to absent | os9 | +| ``redistribute`` | list | Configures the redistribute list to get information from other routing protocols (see ``redistribute.*``) | os9 | +| ``redistribute.route_type`` | string (required): static,connected | Configures the name of the routing protocol to redistribute | os9 | +| ``redistribute.route_map_name`` | string | Configures the route-map to redistribute | os9 | +| ``redistribute.route_map`` | string: absent,present\* | Deletes the route-map to redistribute if set to absent | os9 | +| ``redistribute.address_type`` | string (required): ipv4,ipv6 | Configures the address type of IPv4 or IPv6 routes | os9 | +| ``redistribute.state`` | string: absent,present\* | Deletes the redistribution information if set to absent | os9 | +| ``state`` | string: absent,present\* | Deletes the local router BGP instance if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_bgp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_bgp* role to configure the BGP network and neighbors. It creates a *hosts* file with the switch details, a *host_vars* file with connection variables and the corresponding role variables. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. This example writes a simple playbook that only references the *os9_bgp* role. The sample host_vars given below is for os9. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_bgp: + asn: 11 + router_id: 192.168.3.100 + maxpath_ibgp: 2 + maxpath_ebgp: 2 + graceful_restart: true + best_path: + as_path: ignore + ignore_router_id: true + med: + - attribute: confed + state: present + - attribute: missing-as-best + state: present + ipv4_network: + - address: 102.1.1.0/30 + state: present + ipv6_network: + - address: "2001:4898:5808:ffa0::/126" + state: present + neighbor: + - ip: 192.168.10.2 + type: ipv4 + remote_asn: 12 + timer: 5 10 + adv_interval: 40 + fall_over: present + default_originate: False + peergroup: per + peergroup_state: present + sender_loop_detect: false + src_loopback: 1 + src_loopback_state: present + distribute_list: + in: aa + in_state: present + ebgp_multihop: 25 + admin: up + state: present + - ip: 2001:4898:5808:ffa2::1 + type: ipv6 + remote_asn: 14 + peergroup: per + peergroup_state: present + distribute_list: + in: aa + in_state: present + src_loopback: 0 + src_loopback_state: present + ebgp_multihop: 255 + admin: up + state: present + - name: peer1 + type: peergroup + remote_asn: 14 + distribute_list: + in: an + in_state: present + out: bb + out_state: present + passive: True + subnet: 10.128.4.192/27 + subnet_state: present + state: present + - ip: 172.20.12.1 + description: O_site2-spine1 + type: ipv4 + remote_asn: 64640 + fall_over: present + ebgp_multihop: 4 + src_loopback: 1 + adv_interval: 1 + timer: 3 9 + send_community: + - type: extended + address_family: + - type: ipv4 + activate: falsesrc_loopback + state: present + - type: l2vpn + activate: true + state: present + admin: up + state: present + redistribute: + - route_type: static + route_map_name: aa + state: present + address_type: ipv4 + - route_type: connected + address_type: ipv6 + state: present + state: present + +**Simple playbook to configure BGP - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_bgp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_bgp/defaults/main.yml b/roles/os9_bgp/defaults/main.yml new file mode 100644 index 0000000..0063029 --- /dev/null +++ b/roles/os9_bgp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_bgp \ No newline at end of file diff --git a/roles/os9_bgp/handlers/main.yml b/roles/os9_bgp/handlers/main.yml new file mode 100644 index 0000000..385a5f7 --- /dev/null +++ b/roles/os9_bgp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_bgp \ No newline at end of file diff --git a/roles/os9_bgp/meta/main.yml b/roles/os9_bgp/meta/main.yml new file mode 100644 index 0000000..62263ac --- /dev/null +++ b/roles/os9_bgp/meta/main.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_bgp role facilitates the configuration of BGP attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 + diff --git a/roles/os9_bgp/tasks/main.yml b/roles/os9_bgp/tasks/main.yml new file mode 100644 index 0000000..aaaad20 --- /dev/null +++ b/roles/os9_bgp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating BGP configuration for os9" + template: + src: os9_bgp.j2 + dest: "{{ build_dir }}/bgp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning BGP configuration for os9" + os9_config: + src: os9_bgp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_bgp/templates/os9_bgp.j2 b/roles/os9_bgp/templates/os9_bgp.j2 new file mode 100644 index 0000000..4bc6791 --- /dev/null +++ b/roles/os9_bgp/templates/os9_bgp.j2 @@ -0,0 +1,351 @@ +#jinja2: trim_blocks: True, lstrip_blocks: True +{########################################## +Purpose: +Configure BGP commands for os9 Devices +os9_bgp: + asn: 12 + router_id: + maxpath_ibgp: 2 + maxpath_ebgp: 2 + best_path: + as_path: ignore + as_path_state: present + ignore_router_id: true + med: + - attribute: confed + state: present + ipv4_network: + - address: 101.1.1.0/30 + state: present + ipv6_network: + - address: "2001:4898:5808:ffa0::/126" + state: present + neighbor: + - type: ipv4 + remote_asn: 11 + ip: 192.168.11.1 + admin: up + sender_loop_detect: false + src_loopback: 0 + src_loopback_state: present + ebgp_multihop: 255 + distribute_list: + in: aa + in_state: present + out: aa + out_state: present + state: present + - type: ipv6 + remote_asn: 14 + ip: 2001:4898:5808:ffa2::1 + sender_loop_detect: false + src_loopback: 0 + src_loopback_state: present + state: present + - type: peer_group + name: peer1 + remote_asn: 6 + subnet: 10.128.3.192/27 + subnet_state: present + admin: up + default_originate: true + sender_loop_detect: false + src_loopback: 1 + src_loopback_state: present + ebgp_multihop: 255 + state: present + redistribute: + - route_type: static + state: present + state: present +################################} +{% if os9_bgp is defined and os9_bgp%} +{% set bgp_vars = os9_bgp %} + +{% if bgp_vars.asn is defined and bgp_vars.asn %} + {% if bgp_vars.state is defined and bgp_vars.state == "absent" %} +no router bgp {{ bgp_vars.asn }} + {% else %} +{# Add Feature to the switch #} +router bgp {{ bgp_vars.asn }} + {% if bgp_vars.router_id is defined %} + {% if bgp_vars.router_id %} + bgp router-id {{ bgp_vars.router_id }} + {% else %} + no bgp router-id + {% endif %} + {% endif %} + + {% if bgp_vars.maxpath_ebgp is defined %} + {% if bgp_vars.maxpath_ebgp %} + maximum-paths ebgp {{ bgp_vars.maxpath_ebgp }} + {% else %} + no maximum-paths ebgp + {% endif %} + {% endif %} + + {% if bgp_vars.maxpath_ibgp is defined %} + {% if bgp_vars.maxpath_ibgp %} + maximum-paths ibgp {{ bgp_vars.maxpath_ibgp }} + {% else %} + no maximum-paths ibgp + {% endif %} + {% endif %} + + {% if bgp_vars.graceful_restart is defined and bgp_vars.graceful_restart %} + {% if bgp_vars.graceful_restart.state is defined and bgp_vars.graceful_restart.state == "present" %} + bgp graceful-restart + {% else %} + no bgp graceful-restart + {% endif %} + {% endif %} + + {% if bgp_vars.best_path is defined and bgp_vars.best_path %} + {% if bgp_vars.best_path.as_path is defined and bgp_vars.best_path.as_path %} + {% if bgp_vars.best_path.as_path_state is defined and bgp_vars.best_path.as_path_state == "absent" %} + no bgp bestpath as-path {{ bgp_vars.best_path.as_path }} + {% else %} + bgp bestpath as-path {{ bgp_vars.best_path.as_path }} + {% endif %} + {% endif %} + {% if bgp_vars.best_path.ignore_router_id is defined %} + {% if bgp_vars.best_path.ignore_router_id %} + bgp bestpath router-id ignore + {% else %} + no bgp bestpath router-id ignore + {% endif %} + {% endif %} + {% if bgp_vars.best_path.med is defined and bgp_vars.best_path.med %} + {% for med in bgp_vars.best_path.med %} + {% if med.attribute is defined and med.attribute %} + {% if med.state is defined and med.state == "absent" %} + no bgp bestpath med {{ med.attribute }} + {% else %} + bgp bestpath med {{ med.attribute }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% if bgp_vars.ipv4_network is defined and bgp_vars.ipv4_network %} + {% for net in bgp_vars.ipv4_network %} + {# remove BGP network announcement #} + {% if net.address is defined and net.address %} + {% if net.state is defined and net.state == "absent" %} + no network {{ net.address }} +{# Add BGP network announcement #} + {% else %} + network {{ net.address }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if bgp_vars.ipv6_network is defined and bgp_vars.ipv6_network %} + address-family ipv6 unicast + {% for net in bgp_vars.ipv6_network %} + {% if net.address is defined and net.address %} + {% if net.state is defined and net.state == "absent" %} + no network {{ net.address }} + {% else %} + network {{ net.address }} + {% endif %} + {% endif %} + {% endfor %} + exit-address-family + {% endif %} + + {% if bgp_vars.neighbor is defined and bgp_vars.neighbor %} + {% for neighbor in bgp_vars.neighbor %} + {% if neighbor.type is defined %} + {% if neighbor.type == "ipv4" or neighbor.type =="ipv6" %} + {% if neighbor.ip is defined and neighbor.ip %} + {% set tag_or_ip = neighbor.ip %} + {% if neighbor.remote_asn is defined and neighbor.remote_asn %} + {% if neighbor.state is defined and neighbor.state == "absent" %} + no neighbor {{ tag_or_ip }} remote-as {{ neighbor.remote_asn }} + {% if neighbor.peergroup is defined and neighbor.peergroup %} + {% if neighbor.peergroup_state is defined and neighbor.peergroup_state == "absent" %} + no neighbor {{ tag_or_ip }} peer-group {{ neighbor.peergroup }} + {% endif %} + {% endif %} + {% if neighbor.type == "ipv6" %} + address-family ipv6 unicast + no neighbor {{ tag_or_ip }} activate + exit-address-family + {% endif %} + {% else %} + neighbor {{ tag_or_ip }} remote-as {{ neighbor.remote_asn }} + {% if neighbor.peergroup is defined and neighbor.peergroup %} + {% if neighbor.peergroup_state is defined and neighbor.peergroup_state == "absent" %} + no neighbor {{ tag_or_ip }} peer-group {{ neighbor.peergroup }} + {% else %} + neighbor {{ tag_or_ip }} peer-group {{ neighbor.peergroup }} + {% endif %} + {% endif %} + {% if neighbor.type == "ipv6" %} + address-family ipv6 unicast + neighbor {{ tag_or_ip }} activate + exit-address-family + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% elif neighbor.type == "peergroup" %} + {% if neighbor.name is defined and neighbor.name %} + {% set tag_or_ip = neighbor.name %} + {% if neighbor.state is defined and neighbor.state == "absent" %} + no neighbor {{ tag_or_ip }} peer-group + {% else %} + {% if neighbor.passive is defined and neighbor.passive %} + neighbor {{ tag_or_ip }} peer-group passive + {% if neighbor.subnet is defined and neighbor.subnet %} + {% if neighbor.subnet_state is defined and neighbor.subnet_state == "absent" %} + no neighbor {{ tag_or_ip }} subnet {{ neighbor.subnet }} + {% else %} + neighbor {{ tag_or_ip }} subnet {{ neighbor.subnet }} + {% endif %} + {% endif %} + {% else %} + neighbor {{ tag_or_ip }} peer-group + {% endif %} + {% if neighbor.remote_asn is defined and neighbor.remote_asn %} + {% if neighbor.remote_asn_state is defined and neighbor.remote_asn_state == "absent" %} + no neighbor {{ tag_or_ip }} remote-as {{ neighbor.remote_asn }} + {% else %} + neighbor {{ tag_or_ip }} remote-as {{ neighbor.remote_asn }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if tag_or_ip is defined and tag_or_ip %} + {% if (neighbor.state is not defined) or (neighbor.state is defined and not neighbor.state == "absent") %} + {% if neighbor.timer is defined %} + {% if neighbor.timer %} + neighbor {{ tag_or_ip }} timers {{ neighbor.timer }} + {% else %} + no neighbor {{ tag_or_ip }} timers + {% endif %} + {% endif %} + {% if neighbor.default_originate is defined %} + {% if neighbor.default_originate %} + neighbor {{ tag_or_ip }} default-originate + {% else %} + no neighbor {{ tag_or_ip }} default-originate + {% endif %} + {% endif %} + {% if neighbor.sender_loop_detect is defined %} + {% if neighbor.sender_loop_detect %} + neighbor {{ tag_or_ip }} sender-side-loop-detection + {% else %} + no neighbor {{ tag_or_ip }} sender-side-loop-detection + {% endif %} + {% endif %} + {% if neighbor.src_loopback is defined and neighbor.src_loopback|int(-1) != -1 %} + {% if neighbor.src_loopback_state is defined and neighbor.src_loopback_state == "absent" %} + no neighbor {{ tag_or_ip }} update-source Loopback {{neighbor.src_loopback }} + {% else %} + neighbor {{ tag_or_ip }} update-source Loopback {{ neighbor.src_loopback }} + {% endif %} + {% endif %} + {% if neighbor.ebgp_multihop is defined %} + {% if neighbor.ebgp_multihop %} + neighbor {{ tag_or_ip }} ebgp-multihop {{ neighbor.ebgp_multihop }} + {% else %} + no neighbor {{ tag_or_ip }} ebgp-multihop + {% endif %} + {% endif %} + {% if neighbor.distribute_list is defined and neighbor.distribute_list %} + {% if neighbor.distribute_list.in is defined and neighbor.distribute_list.in %} + {% if neighbor.distribute_list.in_state is defined and neighbor.distribute_list.in_state == "absent" %} + no neighbor {{ tag_or_ip }} distribute-list {{ neighbor.distribute_list.in }} in + {% else %} + neighbor {{ tag_or_ip }} distribute-list {{ neighbor.distribute_list.in }} in + {% endif %} + {% endif %} + {% if neighbor.distribute_list.out is defined and neighbor.distribute_list.out %} + {% if neighbor.distribute_list.out_state is defined and neighbor.distribute_list.out_state == "absent" %} + no neighbor {{ tag_or_ip }} distribute-list {{ neighbor.distribute_list.out }} out + {% else %} + neighbor {{ tag_or_ip }} distribute-list {{ neighbor.distribute_list.out }} out + {% endif %} + {% endif %} + {% endif %} + {% if neighbor.admin is defined and (neighbor.admin == "up" or neighbor.admin == "present") %} + neighbor {{ tag_or_ip }} no shutdown + {% else %} + neighbor {{ tag_or_ip }} shutdown + {% endif %} + {% if neighbor.adv_interval is defined %} + {% if neighbor.adv_interval %} + neighbor {{ tag_or_ip }} advertisement-interval {{ neighbor.adv_interval }} + {% else %} + no neighbor {{ tag_or_ip }} advertisement-interval + {% endif %} + {% endif %} + {% if neighbor.fall_over is defined and neighbor.fall_over == "present" %} + neighbor {{ tag_or_ip }} fall-over + {% elif neighbor.fall_over is defined and neighbor.fall_over == "absent" %} + no neighbor {{ tag_or_ip }} fall-over + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if bgp_vars.redistribute is defined and bgp_vars.redistribute %} + {% for route in bgp_vars.redistribute %} + {% if route.route_type is defined and route.route_type %} + {% if route.address_type is defined and route.address_type %} + {% if route.address_type == "ipv6" %} + address-family {{ route.address_type }} unicast + {% if route.state is defined and route.state == "absent" %} + no redistribute {{ route.route_type }} + {% else %} + {% if route.route_map is defined %} + {% if route.route_map == "present" %} + {% if route.route_map_name is defined and route.route_map_name %} + redistribute {{ route.route_type }} route-map {{ route.route_map_name }} + {% else %} + redistribute {{ route.route_type }} + {% endif %} + {% else %} + {% if route.route_map_name is defined and route.route_map_name %} + no redistribute {{ route.route_type }} route-map {{ route.route_map_name }} + {% endif %} + {% endif %} + {% else %} + redistribute {{ route.route_type }} + {% endif %} + {% endif %} + exit-address-family + {% else %} + {% if route.state is defined and route.state == "absent" %} + no redistribute {{ route.route_type }} + {% else %} + {% if route.route_map is defined %} + {% if route.route_map == "present" %} + {% if route.route_map_name is defined and route.route_map_name %} + redistribute {{ route.route_type }} route-map {{ route.route_map_name }} + {% else %} + redistribute {{ route.route_type }} + {% endif %} + {% else %} + {% if route.route_map_name is defined and route.route_map_name %} + no redistribute {{ route.route_type }} route-map {{ route.route_map_name }} + {% endif %} + {% endif %} + redistribute {{ route.route_type }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + +{% endif %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_bgp/tests/inventory.yaml b/roles/os9_bgp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_bgp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_bgp/tests/main.os9.yaml b/roles/os9_bgp/tests/main.os9.yaml new file mode 100644 index 0000000..ed00565 --- /dev/null +++ b/roles/os9_bgp/tests/main.os9.yaml @@ -0,0 +1,97 @@ +--- +# vars file for dellemc.os9.os9_bgp, +# below gives a sample configuration +# Sample variables for OS9 device + os9_bgp: + asn: 11 + router_id: 192.168.3.100 + maxpath_ibgp: 2 + maxpath_ebgp: 2 + best_path: + as_path: ignore + as_path_state: absent + ignore_router_id: true + med: + - attribute: confed + state: present + - attribute: missing-as-best + state: present + ipv4_network: + - address: 102.1.1.0/30 + state: present + ipv6_network: + - address: "2001:4898:5808:ffa0::/126" + state: present + - address: "2001:4898:5808:ffa1::/126" + state: present + neighbor: + - name: per + type: peergroup + remote_asn: 12 + remote_asn_state: absent + default_originate: False + src_loopback: 0 + src_loopback_state: present + ebgp_multihop: 255 + state: present + + - name: peer1 + type: peergroup + remote_asn: 14 + distribute_list: + in: an + in_state: present + out: bb + out_state: present + passive: True + subnet: 10.128.4.192/27 + state: present + + - ip: 192.168.10.2 + type: ipv4 + remote_asn: 12 + timer: 5 10 + default_originate: False + peergroup: per + peergroup_state: present + distribute_list: + in: aa + in_state: present + admin: up + state: present + + - ip: 192.168.13.3 + type: ipv4 + remote_asn: 13 + sender_loop_detect: false + src_loopback: 1 + src_loopback_state: present + distribute_list: + in: aa + in_state: present + out: aa + out_state: present + ebgp_multihop: 25 + state: present + + - ip: 2001:4898:5808:ffa2::1 + type: ipv6 + remote_asn: 14 + peergroup: per + peergroup_state: present + distribute_list: + in: aa + in_state: present + src_loopback: 0 + src_loopback_state: present + ebgp_multihop: 255 + admin: up + state: present + redistribute: + - route_type: static + state: present + address_type: ipv4 + - route_type: connected + address_type: ipv6 + state: present + state: present \ No newline at end of file diff --git a/roles/os9_bgp/tests/test.yaml b/roles/os9_bgp/tests/test.yaml new file mode 100644 index 0000000..15511b4 --- /dev/null +++ b/roles/os9_bgp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_bgp \ No newline at end of file diff --git a/roles/os9_bgp/vars/main.yml b/roles/os9_bgp/vars/main.yml new file mode 100644 index 0000000..3482e5c --- /dev/null +++ b/roles/os9_bgp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_bgp \ No newline at end of file diff --git a/roles/os9_copy_config/LICENSE b/roles/os9_copy_config/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_copy_config/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_copy_config/README.md b/roles/os9_copy_config/README.md new file mode 100644 index 0000000..515a773 --- /dev/null +++ b/roles/os9_copy_config/README.md @@ -0,0 +1,136 @@ +Copy-config role +================ + +This role is used to push the backup running configuration into a Dell EMC Networking device running OS9, and merges the configuration in the template file with the running configuration of the device. + +The copy_config role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- No predefined variables are part of this role +- Use *host_vars* or *group_vars* as part of the template file +- Configuration file is host-specific +- Copy the host-specific configuration to the respective file under the template directory in *.j2* format +- Variables and values are case-sensitive + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_copy_config* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_copy_config* role to push the configuration file into the device. It creates a *hosts* file with the switch details and corresponding variables. It writes a simple playbook that only references the *os9_copy_config* role. By including the role, you automatically get access to all of the tasks to push configuration file. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + + # This variable shall be applied in the below jinja template for each host by defining here + os9_bgp + asn: 64801 + +**Sample roles/os9_copy_config/templates/leaf1.j2** + + ! Leaf1 BGP profile on Dell OS9 switch + snmp-server community public ro + hash-algorithm ecmp crc + ! + interface ethernet1/1/1:1 + no switchport + ip address 100.1.1.2/24 + ipv6 address 2001:100:1:1::2/64 + mtu 9216 + no shutdown + ! + interface ethernet1/1/9:1 + no switchport + ip address 100.2.1.2/24 + ipv6 address 2001:100:2:1::2/64 + mtu 9216 + no shutdown + ! + router bgp {{ os9_bgp.asn }} + bestpath as-path multipath-relax + bestpath med missing-as-worst + router-id 100.0.2.1 + ! + address-family ipv4 unicast + ! + address-family ipv6 unicast + ! + neighbor 100.1.1.1 + remote-as 64901 + no shutdown + ! + neighbor 100.2.1.1 + remote-as 64901 + no shutdown + ! + neighbor 2001:100:1:1::1 + remote-as 64901 + no shutdown + ! + address-family ipv4 unicast + no activate + exit + ! + address-family ipv6 unicast + activate + exit + ! + neighbor 2001:100:2:1::1 + remote-as 64901 + no shutdown + ! + address-family ipv4 unicast + no activate + exit + ! + address-family ipv6 unicast + activate + exit + ! + +**Simple playbook to setup to push configuration file into device - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_copy_config + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_copy_config/defaults/main.yml b/roles/os9_copy_config/defaults/main.yml new file mode 100644 index 0000000..7f52794 --- /dev/null +++ b/roles/os9_copy_config/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_copy_config \ No newline at end of file diff --git a/roles/os9_copy_config/handlers/main.yml b/roles/os9_copy_config/handlers/main.yml new file mode 100644 index 0000000..69e9baf --- /dev/null +++ b/roles/os9_copy_config/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_copy_config \ No newline at end of file diff --git a/roles/os9_copy_config/meta/main.yml b/roles/os9_copy_config/meta/main.yml new file mode 100644 index 0000000..ff95816 --- /dev/null +++ b/roles/os9_copy_config/meta/main.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: > + This role shall be used to push the backup running configuration into the device. + This role shall merge the configuration in the template file with the running configuration of the device + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 + diff --git a/roles/os9_copy_config/tasks/main.yml b/roles/os9_copy_config/tasks/main.yml new file mode 100644 index 0000000..9da6c39 --- /dev/null +++ b/roles/os9_copy_config/tasks/main.yml @@ -0,0 +1,7 @@ +--- +# tasks file for dellemc.os9.os9_copy_config + - name: "Merge the config file to running configuration for OS9" + os9_config: + src: "{{ hostname }}.j2" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 \ No newline at end of file diff --git a/roles/os9_copy_config/templates/os9_copy_config.j2 b/roles/os9_copy_config/templates/os9_copy_config.j2 new file mode 100644 index 0000000..bb0e16e --- /dev/null +++ b/roles/os9_copy_config/templates/os9_copy_config.j2 @@ -0,0 +1,3 @@ +! Version 10.3.0E +! Last configuration change at May 09 21:47:35 2017 +! \ No newline at end of file diff --git a/roles/os9_copy_config/tests/inventory.yaml b/roles/os9_copy_config/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_copy_config/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_copy_config/tests/main.os9.yaml b/roles/os9_copy_config/tests/main.os9.yaml new file mode 100644 index 0000000..73b314f --- /dev/null +++ b/roles/os9_copy_config/tests/main.os9.yaml @@ -0,0 +1 @@ +--- \ No newline at end of file diff --git a/roles/os9_copy_config/tests/test.yaml b/roles/os9_copy_config/tests/test.yaml new file mode 100644 index 0000000..e2fb514 --- /dev/null +++ b/roles/os9_copy_config/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + connection: network_cli + roles: + - dellemc.os9.os9_copy_config diff --git a/roles/os9_copy_config/vars/main.yml b/roles/os9_copy_config/vars/main.yml new file mode 100644 index 0000000..21269be --- /dev/null +++ b/roles/os9_copy_config/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_copy_config diff --git a/roles/os9_dcb/LICENSE b/roles/os9_dcb/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_dcb/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_dcb/README.md b/roles/os9_dcb/README.md new file mode 100644 index 0000000..5102866 --- /dev/null +++ b/roles/os9_dcb/README.md @@ -0,0 +1,138 @@ +DCB role +======== + +This role facilitates the configuration of data center bridging (DCB). It supports the configuration of the DCB map and the DCB buffer, and assigns them to interfaces. This role is abstracted for Dell EMC platfroms running OS9. + +The DCB role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable and can take the dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_dcb keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``dcb_enable`` | boolean: true,false | Enables/disables DCB | os9 | +| ``dcb_map`` | list | Configures the DCB map (see ``dcb_map.*``) | os9 | +| ``dcb_map.name`` | string (required) | Configures the DCB map name | os9 | +| ``dcb_map.priority_group`` | list | Configures the priority-group for the DCB map (see ``priority_group.*``) | os9 | +| ``priority_group.pgid`` | integer (required): 0-7 | Configures the priority-group ID | os9 | +| ``priority_group.bandwidth`` | integer (required) | Configures the bandwidth percentage for the priority-group | os9 | +| ``priority_group.pfc`` | boolean: true,false (required) | Configures PFC on/off for the priorities in the priority-group | os9 | +| ``priority_group.state`` | string: absent,present\* | Deletes the priority-group of the DCB map if set to absent | os9 | +| ``dcb_map.priority_pgid`` |string (required) | Configures priority to priority-group mapping; value is the PGID of priority groups separated by a space (1 1 2 2 3 3 3 4) | os9 | +| ``dcb_map.intf`` | list | Configures the DCB map to the interface (see ``intf.*``) | os9 | +| ``intf.name`` | string (required) | Configures the DCB map to the interface with this interface name | os9 | +| ``intf.state`` | string: absent,present\* | Deletes the DCB map from the interface if set to absent | os9 | +| ``dcb_map.state`` | string: absent,present\* | Deletes the DCB map if set to absent | os9 | +| ``dcb_buffer`` | list | Configures the DCB buffer profile (see ``dcb_buffer.*``) | os9 | +| ``dcb_buffer.name`` | string (required) | Configures the DCB buffer profile name | os9 | +| ``dcb_buffer.description`` | string (required) | Configures a description about the DCB buffer profile | os9 | +| ``dcb_buffer.priority_params`` | list | Configures priority flow-control buffer parameters (see ``priority_params.*``)| os9 | +| ``priority_params.pgid`` | integer (required): 0-7 | Specifies the priority-group ID | os9 | +| ``priority_params.buffer_size`` | int (required) | Configures the ingress buffer size (in KB) of the DCB buffer profile | os9 | +| ``priority_params.pause`` | integer | Configures the buffer limit (in KB) for pausing | os9 | +| ``priority_params.resume`` | integer | Configures buffer offset limit (in KB) for resume | os9 | +| ``priority_params.state`` | string: absent,present\* | Deletes the priority flow parameters of the DCB buffer if set to absent | os9 | +| ``dcb_buffer.intf`` | list | Configures the DCB buffer to the interface (see ``intf.*``) | os9 | +| ``intf.name`` | string (required) | Configures the DCB buffer to the interface with this interface name | os9 | +| ``intf.state`` | string: absent,present\* | Deletes the DCB buffer from the interface if set to absent | os9 | +| ``dcb_buffer.state`` | string: absent,present\* | Deletes the DCB buffer profile if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_dcb* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_dcb* role to completely configure DCB map and DCB buffer profiles and assigns it to interfaces. The example creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default it is set to false. It writes a simple playbook that only references the *os9_dcb* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_dcb: + dcb_map: + - name: test + priority_pgid: 0 0 0 3 3 3 3 0 + priority_group: + - pgid: 0 + bandwidth: 20 + pfc: true + state: present + - pgid: 3 + bandwidth: 80 + pfc: true + state: present + intf: + - name: fortyGigE 1/8 + state: present + - name: fortyGigE 1/9 + state: present + state: present + dcb_buffer: + - name: buffer + description: + priority_params: + - pgid: 0 + buffer_size: 5550 + pause: 40 + resume: 40 + state: present + intf: + - name: fortyGigE 1/8 + state: present + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9 + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_dcb/defaults/main.yml b/roles/os9_dcb/defaults/main.yml new file mode 100644 index 0000000..58a9546 --- /dev/null +++ b/roles/os9_dcb/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_dcb \ No newline at end of file diff --git a/roles/os9_dcb/handlers/main.yml b/roles/os9_dcb/handlers/main.yml new file mode 100644 index 0000000..476aabf --- /dev/null +++ b/roles/os9_dcb/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_dcb \ No newline at end of file diff --git a/roles/os9_dcb/meta/main.yml b/roles/os9_dcb/meta/main.yml new file mode 100644 index 0000000..1ba55da --- /dev/null +++ b/roles/os9_dcb/meta/main.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_dcb role facilitates the configuration of Data Center Bridging (DCB) attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 diff --git a/roles/os9_dcb/tasks/main.yml b/roles/os9_dcb/tasks/main.yml new file mode 100644 index 0000000..7d365c4 --- /dev/null +++ b/roles/os9_dcb/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating DCB configuration for os9" + template: + src: os9_dcb.j2 + dest: "{{ build_dir }}/dcb9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning DCB configuration for os9" + os9_config: + src: os9_dcb.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_dcb/templates/os9_dcb.j2 b/roles/os9_dcb/templates/os9_dcb.j2 new file mode 100644 index 0000000..be65400 --- /dev/null +++ b/roles/os9_dcb/templates/os9_dcb.j2 @@ -0,0 +1,216 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################ +Purpose: +Configure DCB commands for os9 Devices +os9_dcb: + dcb_enable: true + dcb_map: + - name: test + priority_pgid: 0 0 0 3 3 3 0 3 + priority_group: + - pgid: 0 + bandwidth: 20 + pfc: true + state: present + - pgid: 3 + bandwidth: 20 + pfc: true + state: present + intf: + - name: fortyGigE 1/8 + state: present + - name: fortyGigE 1/9 + state: present + state: present + dcb_buffer: + - name: buffer + description: + priority_params: + - pgid: 0 + buffer_size: 5550 + pause: 40 + resume: 40 + state: present + intf: + - name: fortyGigE 1/6 + state: present + state: present +################################} +{% if os9_dcb is defined and os9_dcb %} +{% set dcb_vars = os9_dcb %} +{% if dcb_vars.dcb_enable is defined %} + {% if dcb_vars.dcb_enable %} +dcb enable + {% else %} +no dcb enable + {% endif %} +{% endif %} +{% if dcb_vars.dcb_map is defined and dcb_vars.dcb_map %} + {% for map in dcb_vars.dcb_map %} + {% if map.name is defined and map.name %} + {% if map.state is defined and map.state == "absent" %} + {% if map.intf is defined and map.intf %} + {% for intf in map.intf %} + {% if intf.state is defined and intf.state == "absent" %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + no dcb-map {{ map.name }} + exit + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +no dcb-map {{ map.name }} + {% else %} +dcb-map {{ map.name }} + {% set pgid_set = {'value': False} %} + {% if map.priority_group is defined and map.priority_group %} + {% for group in map.priority_group %} + {% if group.pgid is defined and group.pgid >= 0 %} + {% if group.state is defined and group.state == "absent" %} + {% if not pgid_set['value'] %} + {% if map.priority_pgid is defined %} + {% if pgid_set.update({'value': True}) %} {% endif %} + {% if map.priority_pgid %} + priority-pgid {{ map.priority_pgid }} + {% else %} + no priority-pgid + {% endif %} + {% endif %} + {% endif %} + no priority-group {{ group.pgid }} + {% else %} + {% if group.bandwidth is defined and group.bandwidth %} + {% if group.pfc is defined %} + {% if group.pfc %} + priority-group {{ group.pgid }} bandwidth {{ group.bandwidth }} pfc on + {% else %} + priority-group {{ group.pgid }} bandwidth {{ group.bandwidth }} pfc off + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if not pgid_set['value'] %} + {% if map.priority_pgid is defined %} + {% if map.priority_pgid %} + priority-pgid {{ map.priority_pgid }} + {% else %} + no priority-pgid + {% endif %} + {% endif %} + {% endif %} + {% if map.intf is defined and map.intf %} + {% for intf in map.intf %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if intf.state is defined and intf.state == "absent" %} + no dcb-map {{ map.name }} + {% else %} + dcb-map {{ map.name }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% if dcb_vars.dcb_buffer is defined and dcb_vars.dcb_buffer %} + {% for buf in dcb_vars.dcb_buffer %} + {% if buf.name is defined and buf.name %} + {% if buf.state is defined and buf.state == "absent" %} +no dcb-buffer-threshold {{ buf.name }} + {% else %} +dcb-buffer-threshold {{ buf.name }} + {% if buf.description is defined and buf.description %} + description {{ buf.description }} + {% elif buf.description is defined and not buf.description %} + no description + {% endif %} + + {% if buf.priority_params is defined and buf.priority_params %} + {% for params in buf.priority_params %} + {% if params.pgid is defined and params.pgid >= 0 %} + {% if params.state is defined and params.state == "absent" %} + {% if params.buffer_size is defined and params.buffer_size %} + {% if params.pause is defined and params.pause %} + {% if params.resume is defined and params.resume %} + no priority {{ params.pgid }} buffer-size {{ params.buffer_size }} pause-threshold {{ params.pause }} resume-offset {{ params.resume }} + {% else %} + no priority {{ params.pgid }} buffer-size {{ params.buffer_size }} pause-threshold {{ params.pause }} + {% endif %} + {% else %} + {% if params.resume is defined and params.resume %} + no priority {{ params.pgid }} buffer-size {{ params.buffer_size }} resume-offset {{ params.resume }} + {% else %} + no priority {{ params.pgid }} buffer-size {{ params.buffer_size }} + {% endif %} + {% endif %} + {% else %} + {% if params.pause is defined and params.pause %} + {% if params.resume is defined and params.resume %} + no priority {{ params.pgid }} pause-threshold {{ params.pause }} resume-offset {{ params.resume }} + {% else %} + no priority {{ params.pgid }} pause-threshold {{ params.pause }} + {% endif %} + {% else %} + {% if params.resume is defined and params.resume %} + no priority {{ params.pgid }} resume-offset {{ params.resume }} + {% else %} + no priority {{ params.pgid }} + {% endif %} + {% endif %} + {% endif %} + {% else %} + {% if params.buffer_size is defined and params.buffer_size %} + {% if params.pause is defined and params.pause %} + {% if params.resume is defined and params.resume %} + priority {{ params.pgid }} buffer-size {{ params.buffer_size }} pause-threshold {{ params.pause }} resume-offset {{ params.resume }} + {% else %} + priority {{ params.pgid }} buffer-size {{ params.buffer_size }} pause-threshold {{ params.pause }} + {% endif %} + {% else %} + {% if params.resume is defined and params.resume %} + priority {{ params.pgid }} buffer-size {{ params.buffer_size }} resume-offset {{ params.resume }} + {% else %} + priority {{ params.pgid }} buffer-size {{ params.buffer_size }} + {% endif %} + {% endif %} + {% else %} + {% if params.pause is defined and params.pause %} + {% if params.resume is defined and params.resume %} + priority {{ params.pgid }} pause-threshold {{ params.pause }} resume-offset {{ params.resume }} + {% else %} + priority {{ params.pgid }} pause-threshold {{ params.pause }} + {% endif %} + {% else %} + {% if params.resume is defined and params.resume %} + priority {{ params.pgid }} resume-offset {{ params.resume }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if buf.intf is defined and buf.intf %} + {% for intf in buf.intf %} + {% if intf.name is defined and intf.name %} +interface {{ intf.name }} + {% if intf.state is defined and intf.state == "absent" %} + no dcb-policy buffer-threshold {{ buf.name }} + {% else %} + dcb-policy buffer-threshold {{ buf.name }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_dcb/tests/inventory.yaml b/roles/os9_dcb/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_dcb/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_dcb/tests/main.os9.yaml b/roles/os9_dcb/tests/main.os9.yaml new file mode 100644 index 0000000..4c19958 --- /dev/null +++ b/roles/os9_dcb/tests/main.os9.yaml @@ -0,0 +1,38 @@ +--- +# vars file for dellemc.os9.os9_dcb, +# below gives a sample configuration +# Sample variables for OS9 device +os9_dcb: + dcb_enable: true + dcb_map: + - name: test + priority_pgid: 0 0 0 3 0 0 0 0 + priority_group: + - pgid: 0 + bandwidth: 50 + pfc: false + state: present + - pgid: 3 + bandwidth: 50 + pfc: true + state: present + intf: + - name: fortyGigE 1/8 + state: absent + - name: fortyGigE 1/9 + state: present + dcb_buffer: + - name: buffer + description: testbuffer + priority_params: + - pgid: 0 + buffer_size: 70 + pause: 40 + resume: 40 + state: present + intf: + - name: fortyGigE 1/8 + state: present + - name: fortyGigE 1/5 + state: present + state: present \ No newline at end of file diff --git a/roles/os9_dcb/tests/test.yaml b/roles/os9_dcb/tests/test.yaml new file mode 100644 index 0000000..ad59857 --- /dev/null +++ b/roles/os9_dcb/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_dcb \ No newline at end of file diff --git a/roles/os9_dcb/vars/main.yml b/roles/os9_dcb/vars/main.yml new file mode 100644 index 0000000..dec87c7 --- /dev/null +++ b/roles/os9_dcb/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_dcb \ No newline at end of file diff --git a/roles/os9_dns/LICENSE b/roles/os9_dns/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_dns/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_dns/README.md b/roles/os9_dns/README.md new file mode 100644 index 0000000..4edc835 --- /dev/null +++ b/roles/os9_dns/README.md @@ -0,0 +1,97 @@ +DNS role +======== + +This role facilitates the configuration of the domain name service (DNS). This role is abstracted for Dell EMC platforms running OS9 and requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take the dellemc.os9.os9 as a value +- If *os9_cfg_generate* set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_dns keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``name_server`` | list | Configures DNS (see ``name_server.*``) | os9 | +| ``name_server.domain_lookup`` | boolean | Enables or disables domain name lookup | os9 | +| ``name_server.ip`` | list | Configures the name server IP | os9 | +| ``name_server.vrf`` | list | Configures VRF for each IP | os9 | +| ``name_server.state`` | string: absent,present\* | Deletes the name server IP if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_dns* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_dns* role to completely set up the DNS server configuration. The example creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, generates the configuration commands as a .part file in *build_dir* path. By default it is set to false. It writes a simple playbook that only references the *os9_dns* role. By including the role, you automatically get access to all of the tasks to configure DNS. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_dns: + domain_lookup: true + name_server: + - ip: + - 1.1.1.1 + - 1.1.1.2 + vrf: + - test + - management + state: absent + - ip: + - 2.2.2.2 + - ip: + - 3.3.2.2 + state: absent + +**Simple playbook to setup DNS - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_dns + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_dns/defaults/main.yml b/roles/os9_dns/defaults/main.yml new file mode 100644 index 0000000..a5b36f9 --- /dev/null +++ b/roles/os9_dns/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_dns \ No newline at end of file diff --git a/roles/os9_dns/handlers/main.yml b/roles/os9_dns/handlers/main.yml new file mode 100644 index 0000000..4e8ac24 --- /dev/null +++ b/roles/os9_dns/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_dns \ No newline at end of file diff --git a/roles/os9_dns/meta/main.yml b/roles/os9_dns/meta/main.yml new file mode 100644 index 0000000..eb190a6 --- /dev/null +++ b/roles/os9_dns/meta/main.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_dns role facilitates the configuration DNS attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 diff --git a/roles/os9_dns/tasks/main.yml b/roles/os9_dns/tasks/main.yml new file mode 100644 index 0000000..fff8ef1 --- /dev/null +++ b/roles/os9_dns/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating DNS configuration for os9" + template: + src: os9_dns.j2 + dest: "{{ build_dir }}/dns9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning DNS configuration for os9" + os9_config: + src: os9_dns.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_dns/templates/os9_dns.j2 b/roles/os9_dns/templates/os9_dns.j2 new file mode 100644 index 0000000..12f013a --- /dev/null +++ b/roles/os9_dns/templates/os9_dns.j2 @@ -0,0 +1,111 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{#################################### +Purpose: +Configure DNS commands for os9 devices +os9_dns: + domain_lookup: true + domain_name: dns.search.name + name_server: + - ip: + - 3.1.1.1 + - 3.1.1.2 + vrf: + - test + - test1 + - vrf: + - test1 + state: absent + - ip: + - 2.2.2.2 + - ip: + - 3.3.2.2 + state: absent + domain_list: + - vrf: + - test + - test1 + state: absent + - name: + - dname3 + - dname4 + - name: + - dname5 + - dname6 + state: absent + - name: + - dname7 + - dname8 + vrf: + - test + - test1 +#####################################} +{% if (os9_dns is defined and os9_dns) %} + {% if os9_dns.domain_lookup is defined and os9_dns.domain_lookup == true %} + ip domain-lookup + {% elif os9_dns.domain_lookup is defined and os9_dns.domain_lookup == false %} + no ip domain-lookup + {% endif %} + {% if os9_dns.domain_name is defined and os9_dns.domain_name %} + ip domain-name {{ os9_dns.domain_name }} + {% elif os9_dns.domain_name is defined and os9_dns.domain_name %} + no ip domain-name {{ os9_dns.domain_name }} + {% endif %} + {% if (os9_dns.name_server is defined and os9_dns.name_server) %} + {% for name_server in os9_dns.name_server %} + {% set absent = "" %} + {% if name_server.state is defined and name_server.state == "absent" %} + {% set absent = "no " %} + {% endif %} + + {% set vrf_name_list = name_server.vrf %} + {% if (vrf_name_list is defined and vrf_name_list ) %} + {% for vrf_name in vrf_name_list %} + {% set ip_list = name_server.ip %} + {% if (ip_list is defined and ip_list ) %} + {% for ip_val in ip_list %} + {{ absent }}ip name-server vrf {{ vrf_name }} {{ ip_val }} + {% endfor %} + {% elif name_server.state is defined and name_server.state == "absent"%} + {{ absent }}ip name-server vrf {{ vrf_name }} + {% endif %} + {% endfor %} + {% else %} + {% set ip_list = name_server.ip %} + {% if (ip_list is defined and ip_list ) %} + {% for ip_val in ip_list %} + {{ absent }}ip name-server {{ ip_val }} + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if (os9_dns.domain_list is defined and os9_dns.domain_list) %} + {% for domain in os9_dns.domain_list %} + {% set absent = "" %} + {% if domain.state is defined and domain.state == "absent" %} + {% set absent = "no " %} + {% endif %} + + {% set vrf_name_list = domain.vrf %} + {% if (vrf_name_list is defined and vrf_name_list ) %} + {% for vrf_name in vrf_name_list %} + {% set name_list = domain.name %} + {% if (name_list is defined and name_list ) %} + {% for name_val in name_list %} + {{ absent }}ip domain-list vrf {{ vrf_name }} {{ name_val }} + {% endfor %} + {% elif domain.state is defined and domain.state == "absent"%} + {{ absent }}ip domain-list vrf {{ vrf_name }} + {% endif %} + {% endfor %} + {% else %} + {% set name_list = domain.name %} + {% if (name_list is defined and name_list ) %} + {% for name_val in name_list %} + {{ absent }}ip domain-list {{ name_val }} + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_dns/tests/inventory.yaml b/roles/os9_dns/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_dns/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_dns/tests/main.os9.yaml b/roles/os9_dns/tests/main.os9.yaml new file mode 100644 index 0000000..28efa04 --- /dev/null +++ b/roles/os9_dns/tests/main.os9.yaml @@ -0,0 +1,40 @@ +--- +# vars file for dellemc.os9.os9_dns, +# below gives a sample configuration +# Sample variables for OS9 device +os9_dns: + domain_lookup: true + name_server: + - ip: + - 3.1.1.1 + - 3.1.1.2 + vrf: + - test + - test1 + - vrf: + - test1 + state: absent + - ip: + - 2.2.2.2 + state: absent + - ip: + - 3.3.2.2 + state: absent + domain_list: + - vrf: + - test + - test1 + state: absent + - name: + - dname3 + - dname4 + - name: + - dname5 + - dname6 + state: absent + - name: + - dname7 + - dname8 + vrf: + - test + - test1 \ No newline at end of file diff --git a/roles/os9_dns/tests/test.yaml b/roles/os9_dns/tests/test.yaml new file mode 100644 index 0000000..8794248 --- /dev/null +++ b/roles/os9_dns/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_dns \ No newline at end of file diff --git a/roles/os9_dns/vars/main.yml b/roles/os9_dns/vars/main.yml new file mode 100644 index 0000000..e5d083a --- /dev/null +++ b/roles/os9_dns/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_dns \ No newline at end of file diff --git a/roles/os9_ecmp/LICENSE b/roles/os9_ecmp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_ecmp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_ecmp/README.md b/roles/os9_ecmp/README.md new file mode 100644 index 0000000..6077eaa --- /dev/null +++ b/roles/os9_ecmp/README.md @@ -0,0 +1,94 @@ +ECMP role +========= + +This role facilitates the configuration of equal cost multi-path (ECMP). It supports the configuration of ECMP for IPv4, and is abstracted for Dell EMC platforms running OS9. + +The ECMP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take the dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_ecmp keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``weighted_ecmp`` | boolean: true,false | Configures weighted ECMP | os9 | +| ``ecmp_group_max_paths`` | integer | Configures the number of maximum-paths per ecmp-group | os9 | +| ``ecmp_group_path_fallback`` | boolean: true,false | Configures ECMP group path management | os9 | +| ``ecmp `` | dictionary | Configures ECMP group (see ``ecmp .*``) | os9 | +| ``ecmp .interface`` | list | Configures interface into an ECMP group | os9 | +| ``ecmp .link_bundle_monitor`` | boolean: true,false | Configures link-bundle monitoring | os9 | +| ``ecmp .state`` | string: present\*,absent | Deletes the ECMP group if set to absent | os9 | + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_ecmp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_ecmp* role to configure ECMP for IPv4. The example creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with the corresponding Dell EMC Networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. The example writes a simple playbook that only references the *os9_ecmp* role. The sample *host_vars* is provided for os9 only. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_ecmp: + ecmp 1: + interface: + - fortyGigE 1/49 + - fortyGigE 1/51 + link_bundle_monitor: true + state: present + weighted_ecmp: true + ecmp_group_max_paths: 3 + ecmp_group_path_fallback: true + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_ecmp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_ecmp/defaults/main.yml b/roles/os9_ecmp/defaults/main.yml new file mode 100644 index 0000000..8c84dde --- /dev/null +++ b/roles/os9_ecmp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_ecmp \ No newline at end of file diff --git a/roles/os9_ecmp/handlers/main.yml b/roles/os9_ecmp/handlers/main.yml new file mode 100644 index 0000000..99b79b6 --- /dev/null +++ b/roles/os9_ecmp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_ecmp \ No newline at end of file diff --git a/roles/os9_ecmp/meta/main.yml b/roles/os9_ecmp/meta/main.yml new file mode 100644 index 0000000..1833ca6 --- /dev/null +++ b/roles/os9_ecmp/meta/main.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_ecmp role facilitates the configuration of ECMP group attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 diff --git a/roles/os9_ecmp/tasks/main.yml b/roles/os9_ecmp/tasks/main.yml new file mode 100644 index 0000000..265ea6a --- /dev/null +++ b/roles/os9_ecmp/tasks/main.yml @@ -0,0 +1,17 @@ +--- +# tasks file for os9 + + - name: "Generating ECMP configuration for os9" + template: + src: os9_ecmp.j2 + dest: "{{ build_dir }}/ecmp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning ECMP configuration for os9" + os9_config: + src: os9_ecmp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_ecmp/templates/os9_ecmp.j2 b/roles/os9_ecmp/templates/os9_ecmp.j2 new file mode 100644 index 0000000..0517646 --- /dev/null +++ b/roles/os9_ecmp/templates/os9_ecmp.j2 @@ -0,0 +1,62 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{#################################### +Purpose: +Configure ECMP commands for os9 devices +os9_ecmp: + weighted_ecmp: true + ecmp_group_max_paths: 3 + ecmp_group_path_fallback: true + ecmp 1: + interface: + - fortyGigE 1/49 + - fortyGigE 1/51 + link_bundle_monitor: true + state: present +#####################################} +{% if os9_ecmp is defined and os9_ecmp %} + {% if os9_ecmp.weighted_ecmp is defined %} + {% if os9_ecmp.weighted_ecmp %} +ip ecmp weighted + {% else %} +no ip ecmp weighted + {% endif %} + {% endif %} + {% if os9_ecmp.ecmp_group_max_paths is defined %} + {% if os9_ecmp.ecmp_group_max_paths %} +ip ecmp-group maximum-paths {{ os9_ecmp.ecmp_group_max_paths }} + {% else %} +no ip ecmp-group maximum-paths 2 + {% endif %} + {% endif %} + {% if os9_ecmp.ecmp_group_path_fallback is defined %} + {% if os9_ecmp.ecmp_group_path_fallback %} +ip ecmp-group path-fallback + {% else %} +no ip ecmp-group path-fallback + {% endif %} + {% endif %} + + {% for key in os9_ecmp.keys() %} + {% if " " in key %} + {% set ecmp_vars = os9_ecmp[key] %} + {% set group_num = key.split(" ") %} + {% if ecmp_vars.state is defined and ecmp_vars.state == "absent" %} +no ecmp-group {{ group_num[1] }} + {% else %} +ecmp-group {{ group_num[1] }} + {% if ecmp_vars.interface is defined and ecmp_vars.interface %} + {% for intf in ecmp_vars.interface %} + interface {{ intf }} + {% endfor %} + {% endif %} + {% if ecmp_vars.link_bundle_monitor is defined %} + {% if ecmp_vars.link_bundle_monitor %} + link-bundle-monitor enable + {% else %} + no link-bundle-monitor enable + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_ecmp/tests/inventory.yaml b/roles/os9_ecmp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_ecmp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_ecmp/tests/main.os9.yaml b/roles/os9_ecmp/tests/main.os9.yaml new file mode 100644 index 0000000..00bb8af --- /dev/null +++ b/roles/os9_ecmp/tests/main.os9.yaml @@ -0,0 +1,14 @@ +--- +# vars file for dellemc.os9.os9_ecmp, +# below gives a sample configuration +# Sample variables for OS9 device +os9_ecmp: + ecmp 1: + interface: + - fortyGigE 1/49 + - fortyGigE 1/51 + link_bundle_monitor: true + state: present + weighted_ecmp: true + ecmp_group_max_paths: 3 + ecmp_group_path_fallback: true \ No newline at end of file diff --git a/roles/os9_ecmp/tests/test.yaml b/roles/os9_ecmp/tests/test.yaml new file mode 100644 index 0000000..6c4fea5 --- /dev/null +++ b/roles/os9_ecmp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_ecmp \ No newline at end of file diff --git a/roles/os9_ecmp/vars/main.yml b/roles/os9_ecmp/vars/main.yml new file mode 100644 index 0000000..532506f --- /dev/null +++ b/roles/os9_ecmp/vars/main.yml @@ -0,0 +1,3 @@ + +--- +# vars file for dellemc.os9.os9_ecmp \ No newline at end of file diff --git a/roles/os9_interface/LICENSE b/roles/os9_interface/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_interface/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_interface/README.md b/roles/os9_interface/README.md new file mode 100644 index 0000000..cd433cb --- /dev/null +++ b/roles/os9_interface/README.md @@ -0,0 +1,178 @@ +Interface role +============== + +This role facilitates the configuration of interface attributes. It supports the configuration of admin state, description, MTU, IP address, IP helper, suppress_ra and port mode. This role is abstracted for Dell EMC platforms running OS9. + +The interface role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable setting to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- *os9_interface* (dictionary) holds a dictionary with the interface name; interface name can correspond to any of the valid OS interfaces with the unique interface identifier name +- For physical interfaces, the interface name must be in * * format; for logical interfaces, the interface must be in * * format; physical interface name can be *fortyGigE 1/1* for os9 devices +- For interface ranges, the interface name must be in *range * format; +- Logical interface names can be *vlan 1* or *port-channel 1* for os9 devices +- Variables and values are case-sensitive + +> **NOTE**: Only define supported variables for the interface type. For example, do not define the *switchport* variable for a logical interface; do not configure portmode when *switchport* is present in os9 devices; + +**interface name keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``desc`` | string | Configures a single line interface description | os9 | +| ``portmode`` | string | Configures port-mode according to the device type | (access and trunk), os9 (hybrid) | +| ``switchport`` | boolean: true,false\* | Configures an interface in L2 mode | os9 | +| ``admin`` | string: up,down\* | Configures the administrative state for the interface; configuring the value as administratively "up" enables the interface; configuring the value as administratively "down" disables the interface | os9 | +| ``mtu`` | integer | Configures the MTU size for L2 and L3 interfaces; example, MTU range is 594 to 12000 for os9 devices, 1280 to 65535 o devices, and set globally on devices | os9 | +| ``fanout`` | string:dual, single, quad (os9); string:10g-4x, 40g-1x, 25g-4x, 100g-1x, 50g-2x) | Configures fanout to the appropriate value in os9* devices.| os9 | +| ``fanout_speed`` | string: 10G, 25G, 40G, 50G | Configures speed for the fanout port based on the fanout mode specified | os9 | +| ``fanout_state`` | string: present, absent* | Configures the fanout mode to a port if state is set to present | os9 | +| ``keepalive`` | boolean: true,false | Configures keepalive on the port if set to true | os9 | +| ``speed`` | string:10,100,1000,auto | Configures interface speed parameters | os9 | +| ``duplex`` | string: full,half | Configures interface duplex parameters | os9 | +| ``auto_neg`` | boolean: true,false | Configures auto-negotiation mode if set to true | os9 | +| ``cr4_auto_neg`` | boolean: true,false | Configures auto-negotiation mode on a CR4 interface type if set to true | os9 | +| ``suppress_ra`` | string; present,absent | Configures IPv6 router advertisements if set to present | os9 | +| ``ip_type_dynamic`` | boolean: true,false | Configures IP address DHCP if set to true (*ip_and_mask* is ignored if set to true) | os9 | +| ``ipv6_type_dynamic`` | boolean: true,false | Configures an IPv6 address for DHCP if set to true (*ipv6_and_mask* is ignored if set to true) | +| ``ipv6_autoconfig`` | boolean: true,false | Configures stateless configuration of IPv6 addresses if set to true (*ipv6_and_mask* is ignored if set to true) | +| ``class_vendor_identifier`` | string: present,absent,string | Configures the vendor-class identifier without a user-defined string if set to present; configures a vendor-class identifier with a user-defined string when a string is specified; ignored when *ip_type_dynamic* is set to false | os9 | +| ``option82`` | boolean: true,false\* | Configures option82 with the remote-id MAC address if *remote_id* is undefined; ignored when *ip_type_dynamic* is set to false | os9 | +| ``remote_id`` |string: hostname,mac,string | Configures option82 with the specified *remote-id*; ignored when *option82* is set to false | os9 | +| ``vrf`` | string | Configures the specified VRF to be associated to the interface o devices | +| ``min_ra`` | string | Configures RA minimum interval time period | +| ``max_ra`` | string | Configures RA maximum interval time period | +| ``ip_and_mask`` | string | Configures the specified IP address to the interface on os9 an devices; configures the specified IP address to the interface VLAN on devices (192.168.11.1/24 format) | os9 | +| ``ip_and_mask_secondary`` | string | Configures the specified IP address as secondary address to the interface on os9 an devices (192.168.11.2/24 format) | os9 | +| ``ip_virtual_gateway_ip`` | string | Configures an anycast gateway IP address for a VXLAN virtual network | +| ``secondary_ip_state`` | string: absent,present\* | Deletes the secondary IP address if set to absent | os9 | +| ``ipv6_and_mask`` | string | Configures a specified IPv6 address to the interface on os9 an devices; configures a specified IP address to the interface VLAN on devices (2001:4898:5808:ffa2::1/126 format) | os9 | +| ``state_ipv6`` | string: absent,present\* | Deletes the IPV6 address if set to absent | +| ``ipv6_reachabletime`` | integer | Configures the reachability time for IPv6 neighbor discovery (0 to 3600000) | os9 | +| ``ip_helper`` | list | Configures DHCP server address objects (see ``ip_helper.*``) | os9 | +| ``ip_helper.ip`` | string (required) | Configures the IPv4 address of the DHCP server (A.B.C.D format) | os9 | +| ``ip_helper.state`` | string: absent,present\* | Deletes the IP helper address if set to absent | os9 | + +> **NOTE**: Asterisk (*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | /os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_interface* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_interface* role to set up description, MTU, admin status, portmode, and switchport details for an interface. The example creates a *hosts* file with the switch details and orresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, this variable is set to false. The example writes a simple playbook that only references the *os9_interface* role. + +**Sample hosts file** + + leaf3 ansible_host= + +**Sample host_vars/leaf3** + + hostname: "leaf3" + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_interface: + TenGigabitEthernet 1/8: + desc: "Connected to Spine1" + portmode: + switchport: False + mtu: 2500 + admin: up + auto_neg: true + speed: auto + duplex: full + keepalive: true + ipv6_and_mask: 2001:4898:5808:ffa2::5/126 + suppress_ra : present + ip_type_dynamic: true + ip_and_mask: 192.168.23.22/24 + class_vendor_identifier: present + option82: true + remote_id: hostname + fortyGigE 1/9: + desc: "Connected to Spine2" + switchport: False + mtu: 2500 + admin: up + cr4_auto_neg: true + ip_and_mask: 192.168.234.20/31 + ip_and_mask_secondary: "192.168.234.21/31" + secondary_ip_state: present + suppress_ra: absent + ip_type_dynamic: false + class_vendor_identifier: absent + option82: true + remote_id: hostname + ipv6_and_mask: 2001:4898:5808:ffa2::9/126 + flowcontrol: + mode: "receive" + enable: "on" + state: "present" + vlan 100: + mtu: 4096 + admin: down + ip_and_mask: + ipv6_and_mask: 2002:4898:5408:faaf::1/64 + suppress_ra: present + state_ipv6: absent + ip_helper: + - ip: 10.0.0.36 + state: absent + ipv6_reachabletime: 600000 + virtual-network 888: + vrf: "green" + desc: "virtual-network interface" + ip_and_mask: "172.17.17.251/24" + ip_virtual_gateway_ip: "172.17.17.1" + admin: up + vlan 20: + suppress_ra: absent + min_ra: 3 + max_ra: 4 + admin: up + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf3 + roles: + - dellemc.os9.os9_interface + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_interface/defaults/main.yml b/roles/os9_interface/defaults/main.yml new file mode 100644 index 0000000..7c8c24e --- /dev/null +++ b/roles/os9_interface/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_interface \ No newline at end of file diff --git a/roles/os9_interface/handlers/main.yml b/roles/os9_interface/handlers/main.yml new file mode 100644 index 0000000..617eb3f --- /dev/null +++ b/roles/os9_interface/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_interface \ No newline at end of file diff --git a/roles/os9_interface/meta/main.yml b/roles/os9_interface/meta/main.yml new file mode 100644 index 0000000..f396d90 --- /dev/null +++ b/roles/os9_interface/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_interface role facilitates the configuration of interface attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_interface/tasks/main.yml b/roles/os9_interface/tasks/main.yml new file mode 100644 index 0000000..a1bc686 --- /dev/null +++ b/roles/os9_interface/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating interface configuration for os9" + template: + src: os9_interface.j2 + dest: "{{ build_dir }}/intf9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os== "dellemc.os9.os9") and (os9_cfg_generate | default('False') | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning interface configuration for os9" + os9_config: + src: os9_interface.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_interface/templates/os9_interface.j2 b/roles/os9_interface/templates/os9_interface.j2 new file mode 100644 index 0000000..7cc1ede --- /dev/null +++ b/roles/os9_interface/templates/os9_interface.j2 @@ -0,0 +1,237 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################################### +Purpose: +Configure interface commands for os9 Devices. +os9_interface: + TenGigabitEthernet 1/36: + desc: "OS9 intf" + portmode: hybrid + mtu: 2000 + switchport: False + admin: up + auto_neg: true + keepalive: true + ip_and_mask: "192.168.13.1/24" + ip_and_mask_secondary: "192.168.14.1/24" + secondary_ip_state: present + suppress_ra: present + ip_type_dynamic: true + ipv6_and_mask: 2001:4898:5808:ffa2::9/126 + ipv6_reachabletime: 60000 + ip_helper: + - ip: 10.0.0.33 + state: present + class_vendor_identifier: present + option82: true + remote_id: hostname + speed: auto + duplex: half + fortyGigE 1/1: + fanout: single + fanout_speed: 40G + fanout_state: present + fortyGigE 0/8: + cr4_auto_neg: true +####################################################} +{% if os9_interface is defined and os9_interface %} +{% for key in os9_interface.keys() %} + {% set intf_vars = os9_interface[key] %} + {% set intf = key.split(" ") %} + {% set port = intf[1].split('/') %} + {% if intf_vars.fanout is defined %} + {% if intf_vars.fanout %} + {% if intf_vars.fanout_state is defined and intf_vars.fanout_state == "present" %} + {% if intf_vars.fanout_speed is defined and intf_vars.fanout_speed %} +stack-unit {{ port[0] }} port {{ port[1] }} portmode {{ intf_vars.fanout}} speed {{ intf_vars.fanout_speed }} no-confirm + {% else %} +stack-unit {{ port[0] }} port {{ port[1] }} portmode {{ intf_vars.fanout }} no-confirm + {% endif %} + {% else %} +no stack-unit {{ port[0] }} port {{ port[1] }} portmode {{ intf_vars.fanout }} no-confirm + {% endif %} + {% endif %} + {% endif %} +{% endfor %} +{% for key in os9_interface.keys() %} +{% set intf_vars = os9_interface[key] %} +{% set intf = key.split(" ") %} +{% set port = intf[1].split('/') %} + {% if (intf_vars.fanout is defined and not intf_vars.fanout) or (intf_vars.fanout is not defined)%} +interface {{ key }} + {% if intf_vars.desc is defined %} + {% if intf_vars.desc %} + description {{ intf_vars.desc }} + {% else %} + no description + {% endif %} + {% endif %} + + {% if intf_vars.portmode is defined %} + {% if intf_vars.switchport is defined and intf_vars.switchport == False %} + no switchport + {% endif %} + {% if intf_vars.portmode %} + portmode {{ intf_vars.portmode}} + {% else %} + no portmode hybrid + {% endif %} + {% endif %} + + {% if intf_vars.switchport is defined %} + {% if intf_vars.switchport == True %} + switchport + {% endif %} + {% if intf_vars.portmode is not defined %} + {% if intf_vars.switchport is defined and intf_vars.switchport == False %} + no switchport + {% endif %} + {% endif %} + {% endif %} + + {% if intf_vars.mtu is defined %} + {% if intf_vars.mtu %} + mtu {{ intf_vars.mtu }} + {% else %} + no mtu + {% endif %} + {% endif %} + + {% if intf_vars.keepalive is defined %} + {% if intf_vars.keepalive %} + keepalive + {% else %} + no keepalive + {% endif %} + {% endif %} + + {% if intf_vars.speed is defined %} + {% if intf_vars.speed %} + speed {{ intf_vars.speed }} + {% else %} + no speed + {% endif %} + {% endif %} + + {% if intf_vars.duplex is defined %} + {% if intf_vars.duplex %} + duplex {{ intf_vars.duplex }} + {% else %} + no duplex + {% endif %} + {% endif %} + + {% if intf_vars.auto_neg is defined %} + {% if intf_vars.auto_neg %} + negotiation auto + {% else %} + no negotiation auto + {% endif %} + {% endif %} + + {% if intf_vars.cr4_auto_neg is defined %} + {% if intf_vars.cr4_auto_neg %} + intf-type cr4 autoneg + {% else %} + no intf-type cr4 autoneg + {% endif %} + {% endif %} + + {% if intf_vars.suppress_ra is defined %} + {% if intf_vars.suppress_ra == "present" %} + ipv6 nd suppress-ra + {% else %} + no ipv6 nd suppress-ra + {% endif %} + {% endif %} + + {% if intf_vars.ip_type_dynamic is defined and intf_vars.ip_type_dynamic %} + {% if intf_vars.class_vendor_identifier is defined and intf_vars.class_vendor_identifier == "present" %} + {% if intf_vars.option82 is defined and intf_vars.option82 %} + {% if intf_vars.remote_id is defined and intf_vars.remote_id %} + ip address dhcp vendor-class-identifier relay information-option remote-id {{ intf_vars.remote_id }} + {% else %} + ip address dhcp relay information-option vendor-class-identifier + {% endif %} + {% else %} + ip address dhcp vendor-class-identifier + {% endif %} + + {% elif intf_vars.class_vendor_identifier is defined and (intf_vars.class_vendor_identifier|length >1 and not intf_vars.class_vendor_identifier == "absent") %} + {% if intf_vars.option82 is defined and intf_vars.option82 %} + {% if intf_vars.remote_id is defined and intf_vars.remote_id %} + ip address dhcp relay information-option remote-id {{ intf_vars.remote_id }} vendor-class-identifier {{ intf_vars.class_vendor_identifier }} + {% else %} + ip address dhcp relay information-option vendor-class-identifier {{ intf_vars.class_vendor_identifier }} + {% endif %} + {% else %} + ip address dhcp vendor-class-identifier {{ intf_vars.class_vendor_identifier }} + {% endif %} + + {% else %} + {% if intf_vars.option82 is defined and intf_vars.option82 %} + {% if intf_vars.remote_id is defined and intf_vars.remote_id %} + ip address dhcp relay information-option remote-id {{ intf_vars.remote_id }} + {% else %} + ip address dhcp relay information-option + {% endif %} + {% else %} + ip address dhcp + {% endif %} + {% endif %} + {% else %} + {% if intf_vars.ip_and_mask is defined %} + {% if intf_vars.ip_and_mask %} + ip address {{ intf_vars.ip_and_mask }} + {% else %} + no ip address + {% endif %} + {% endif %} + {% if intf_vars.ip_and_mask_secondary is defined and intf_vars.ip_and_mask_secondary %} + {% if secondary_ip_state is defined and secondary_ip_state == "absent" %} + no ip address {{ intf_vars.ip_and_mask_secondary }} secondary + {% else %} + ip address {{ intf_vars.ip_and_mask_secondary }} secondary + {% endif %} + {% endif %} + {% endif %} + + + {% if intf_vars.ipv6_and_mask is defined %} + {% if intf_vars.ipv6_and_mask %} + ipv6 address {{ intf_vars.ipv6_and_mask }} + {% else %} + no ipv6 address + {% endif %} + {% endif %} + + {% if intf_vars.ipv6_reachabletime is defined %} + {% if intf_vars.ipv6_reachabletime %} + ipv6 nd reachable-time {{ intf_vars.ipv6_reachabletime }} + {% else %} + no ipv6 nd reachable-time + {% endif %} + {% endif %} + + {% if intf_vars.ip_helper is defined and intf_vars.ip_helper %} + {% for helper in intf_vars.ip_helper %} + {% if helper.ip is defined and helper.ip %} + {% if helper.state is defined and helper.state == "absent" %} + no ip helper-address {{ helper.ip }} + {% else %} + ip helper-address {{ helper.ip }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if intf_vars.admin is defined %} + {% if intf_vars.admin == "up" %} + no shutdown + {% elif intf_vars.admin == "down" %} + shutdown + {% endif %} + {% endif %} + + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_interface/tests/inventory.yaml b/roles/os9_interface/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_interface/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_interface/tests/main.os9.yaml b/roles/os9_interface/tests/main.os9.yaml new file mode 100644 index 0000000..7902338 --- /dev/null +++ b/roles/os9_interface/tests/main.os9.yaml @@ -0,0 +1,50 @@ +--- +# vars file for dellemc.os9.os9_interface +# Sample variables for OS9 device +os9_interface: + TenGigabitEthernet 1/3: + desc: "Connected to Spine1" + portmode: + switchport: False + suppress_ra: present + mtu: 2500 + admin: up + auto_neg: true + keepalive: true + speed: auto + duplex: full + ipv6_and_mask: 2001:4898:5808:ffa2::5/126 + ip_type_dynamic: true + ip_and_mask: 192.168.23.22/24 + class_vendor_identifier: present + option82: true + remote_id: hostname + fortyGigE 1/9: + desc: "Connected to Spine2" + switchport: False + mtu: 2500 + admin: up + ip_and_mask: 192.168.234.20/31 + ip_and_mask_secondary: "192.168.14.1/24" + secondary_ip_state: present + cr4_auto_neg: true + keepalive: false + ip_type_dynamic: false + class_vendor_identifier: absent + option82: true + remote_id: hostname + ipv6_and_mask: 2001:4898:5808:ffa2::9/126 + fortyGigE 1/12: + fanout: single + fanout_speed: 40G + fanout_state: present + Vlan 100: + mtu: 4096 + admin: down + ip_and_mask: + ipv6_and_mask: 2002:4898:5408:faaf::1/64 + state_ipv6: absent + ip_helper: + - ip: 10.0.0.36 + state: absent + ipv6_reachabletime: 600000 \ No newline at end of file diff --git a/roles/os9_interface/tests/test.yaml b/roles/os9_interface/tests/test.yaml new file mode 100644 index 0000000..7663d93 --- /dev/null +++ b/roles/os9_interface/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_interface \ No newline at end of file diff --git a/roles/os9_interface/vars/main.yml b/roles/os9_interface/vars/main.yml new file mode 100644 index 0000000..35ddaae --- /dev/null +++ b/roles/os9_interface/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_interface \ No newline at end of file diff --git a/roles/os9_lag/LICENSE b/roles/os9_lag/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_lag/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_lag/README.md b/roles/os9_lag/README.md new file mode 100644 index 0000000..1561b99 --- /dev/null +++ b/roles/os9_lag/README.md @@ -0,0 +1,114 @@ +LAG role +======== + +This role facilitates the configuration of link aggregation group (LAG) attributes, and supports the creation and deletion of a LAG and its member ports. It also supports the configuration of an interface type as a static or dynamic LAG and minimum required link. This role is abstracted for Dell EMC platforms running OS9. + +The LAG role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Object drives the tasks in this role +- *os9_lag* (dictionary) contains the hostname (dictionary) +- Hostname is the value of the *hostname* variable that corresponds to the name of the OS device +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- Any role variable with a corresponding state variable setting to absent negates the configuration of that variable +- Setting an empty value to any variable negates the corresponding configuration +- *os9_lag* (dictionary) holds a dictionary with the port-channel ID key in `Po ` format (1 to 4096 for os9) +- Variables and values are case-sensitive + +**port-channel ID keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``type`` | string: static,dynamic | Configures the interface either as a static or dynamic LAG | os9 | +| ``min_links`` | integer | Configures the minimum number of links in the LAG that must be in *operup* status (1 to 64 for os9) | os9 | +| ``lacp`` | dictionary | Specifies LACP fast-switchover or long timeout options | os9 | +| ``lacp.fast_switchover`` | boolean | Configures the fast-switchover option if set to true | os9 | +| ``lacp.long_timeout`` | boolean | Configures the long-timeout option if set to true | os9 | +| ``lacp_system_priority`` | integer | Configures the LACP system-priority value (1 to 65535 for os9) | os9 | +| ``lacp_ungroup_vlt`` | boolean | Configures all VLT LACP members to be switchports if set to true | os9 | +| ``lacp_ungroup`` | list | Specifies the list of port-channels to become switchports (see ``lacp_ungroup.*``) | os9 | +| ``lacp_ungroup.port_channel`` | integer (required) | Specifies valid port-channel numbers | os9 | +| ``lacp_ungroup.state`` | string: present,absent\* | Deletes the ungroup association if set to absent | os9 | +| ``channel_members`` | list | Specifies the list of port members to be associated to the port-channel (see ``channel_members.*``) | os9 | +| ``channel_members.port`` | string | Specifies valid os9 | os9 | +| ``channel_members.state`` | string: absent,present | Deletes the port member association if set to absent | os9 | +| ``state`` | string: absent,present\* | Deletes the LAG corresponding to the port-channel ID if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_lag* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_lag* role to setup port channel ID and description, and configures hash algorithm and minimum links for the LAG. Channel members can be configured for the port-channel either in static or dynamic mode. You can also delete the LAG with the port-channel ID or delete the members associated to it. This example creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_lag* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_lag: + Po 127: + type: static + min_links: 3 + lacp: + long_timeout: true + fast_switchover: true + lacp_system_priority: 1 + lacp_ungroup_vlt: true + lacp_ungroup: + - port-channel:1 + state: present + channel_members: + - port: fortyGigE 1/4 + state: present + - port: fortyGigE 1/5 + state: present + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_lag + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_lag/defaults/main.yml b/roles/os9_lag/defaults/main.yml new file mode 100644 index 0000000..bcfbb89 --- /dev/null +++ b/roles/os9_lag/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_lag \ No newline at end of file diff --git a/roles/os9_lag/handlers/main.yml b/roles/os9_lag/handlers/main.yml new file mode 100644 index 0000000..cddda15 --- /dev/null +++ b/roles/os9_lag/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_lag \ No newline at end of file diff --git a/roles/os9_lag/meta/main.yml b/roles/os9_lag/meta/main.yml new file mode 100644 index 0000000..08d60b3 --- /dev/null +++ b/roles/os9_lag/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_lag role facilitates the configuration of LAG attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_lag/tasks/main.yml b/roles/os9_lag/tasks/main.yml new file mode 100644 index 0000000..3bb811d --- /dev/null +++ b/roles/os9_lag/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating LAG configuration for os9" + template: + src: os9_lag.j2 + dest: "{{ build_dir }}/lag9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning LAG configuration for os9" + os9_config: + src: os9_lag.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_lag/templates/os9_lag.j2 b/roles/os9_lag/templates/os9_lag.j2 new file mode 100644 index 0000000..f708efc --- /dev/null +++ b/roles/os9_lag/templates/os9_lag.j2 @@ -0,0 +1,114 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################ +Purpose: +Configure LAG commands for os9 Devices. +os9_lag: + Po 1: + type: static + min_links: 3 + lacp: + long_timeout: true + fast_switchover: true + lacp_system_priority: 2 + lacp_ungroup: + - port_channel: 1 + state: present + lacp_ungroup_vlt: true + channel_members: + - port: fortyGigE 0/4 + state: present + state: present + ###############################} +{% if os9_lag is defined and os9_lag %} +{% for key in os9_lag.keys() %} +{% set channel_id = key.split(" ") %} +{% set lag_vars = os9_lag[key] %} + + {% if lag_vars.lacp_system_priority is defined %} + {% if lag_vars.lacp_system_priority %} +lacp system-priority {{ lag_vars.lacp_system_priority }} + {% else %} +no lacp system-priority + {% endif %} + {% endif %} + + {% if lag_vars.lacp_ungroup_vlt is defined %} + {% if lag_vars.lacp_ungroup_vlt %} +lacp ungroup member-independent vlt + {% else %} +no lacp ungroup member-independent vlt + {% endif %} + {% endif %} + + {% if lag_vars.lacp_ungroup is defined %} + {% if lag_vars.lacp_ungroup %} + {% for port in lag_vars.lacp_ungroup %} + {% if port.port_channel is defined and port.port_channel %} + {% if port.state is defined and port.state == "absent" %} +no lacp ungroup member-independent port-channel {{ port.port_channel }} + {% else %} +lacp ungroup member-independent port-channel {{ port.port_channel }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + + {% if lag_vars.state is defined and lag_vars.state == "absent" %} +no interface Port-channel {{ channel_id[1] }} + {% else %} +interface Port-channel {{ channel_id[1] }} + + {% if lag_vars.min_links is defined %} + {% if lag_vars.min_links %} + minimum-links {{ lag_vars.min_links }} + {% else %} + no minimum-links + {% endif %} + {% endif %} + + {% if lag_vars.lacp is defined and lag_vars.lacp %} + {% if lag_vars.lacp.fast_switchover is defined %} + {% if lag_vars.lacp.fast_switchover %} + lacp fast-switchover + {% else %} + no lacp fast-switchover + {% endif %} + {% endif %} + {% if lag_vars.lacp.long_timeout is defined %} + {% if lag_vars.lacp.long_timeout %} + lacp long-timeout + {% else %} + no lacp long-timeout + {% endif %} + {% endif %} + {% endif %} + + {% if lag_vars.channel_members is defined %} + {% for ports in lag_vars.channel_members %} + {% if lag_vars.type is defined and lag_vars.type == "static" %} + {% if ports.port is defined and ports.port %} + {% if ports.state is defined and ports.state == "absent" %} + no channel-member {{ ports.port }} + {% else %} + channel-member {{ ports.port }} + {% endif %} + {% endif %} + {% elif lag_vars.type is defined and lag_vars.type == "dynamic" %} + {% if ports.port is defined and ports.port %} + {% if ports.state is defined and ports.state == "absent" %} +interface {{ ports.port }} + no port-channel-protocol LACP + {% else %} +interface {{ ports.port }} + port-channel-protocol LACP + port-channel {{ channel_id[1] }} mode active + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_lag/tests/inventory.yaml b/roles/os9_lag/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_lag/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_lag/tests/main.os9.yaml b/roles/os9_lag/tests/main.os9.yaml new file mode 100644 index 0000000..cbb19bd --- /dev/null +++ b/roles/os9_lag/tests/main.os9.yaml @@ -0,0 +1,21 @@ +--- +# vars file for dellemc.os9.os9_lag +# Sample variables for os9 device +os9_lag: + Po 127: + type: dynamic + lacp: + long_timeout: true + fast_switchover: true + lacp_ungroup_vlt: true + lacp_system_priority: 1 + lacp_ungroup: + - port_channel: 1 + state: present + min_links: 3 + channel_members: + - port: fortyGigE 1/4 + state: present + - port: fortyGigE 1/8 + state: present + state: present \ No newline at end of file diff --git a/roles/os9_lag/tests/test.yaml b/roles/os9_lag/tests/test.yaml new file mode 100644 index 0000000..0f67293 --- /dev/null +++ b/roles/os9_lag/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_lag \ No newline at end of file diff --git a/roles/os9_lag/vars/main.yml b/roles/os9_lag/vars/main.yml new file mode 100644 index 0000000..cada8d7 --- /dev/null +++ b/roles/os9_lag/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_lag \ No newline at end of file diff --git a/roles/os9_lldp/LICENSE b/roles/os9_lldp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_lldp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_lldp/README.md b/roles/os9_lldp/README.md new file mode 100644 index 0000000..dedbc4b --- /dev/null +++ b/roles/os9_lldp/README.md @@ -0,0 +1,250 @@ +LLDP role +========= + +This role facilitates the configuration of link layer discovery protocol (LLDP) attributes at a global and interface level. It supports the configuration of hello, mode, multiplier, advertise tlvs, management interface, FCoE, ISCSI at global and interface level. This role is abstracted for Dell EMC platforms running OS9. + +The LLDP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_lldp keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``global_lldp_state`` | string: absent,present | Deletes LLDP at a global level if set to absent | os9 | +| ``enable`` | boolean | Enables or disables LLDP at a global level | os9 | +| ``hello`` | integer | Configures the global LLDP hello interval (5 to 180) | os9 | +| ``mode`` | string: rx,tx | Configures global LLDP mode configuration | os9 | +| ``multiplier`` | integer | Configures the global LLDP multiplier (2 to 10) | os9 | +| ``fcoe_priority_bits`` | integer | Configures priority bits for FCoE traffic (1 to FF) | os9 | +| ``iscsi_priority_bits`` | integer | Configures priority bits for ISCSI traffic (1 to FF) | os9 | +| ``dcbx`` | dictionary | Configures DCBx parameters at the global level (see ``dcbx.*``) | os9 | +| ``dcbx.version`` | string | Configures the DCBx version | os9 | +| ``advertise`` | dictionary | Configures LLDP-MED and TLV advertisement at the global level (see ``advertise.*``) | os9 | +| ``advertise.dcbx_tlv`` | string | Configures DCBx TLVs advertisements | os9 | +| ``advertise.dcbx_tlv_state`` | string: present,absent | Deletes DCBx TLVs advertisement if set to absent | os9 | +| ``advertise.dcbx_appln_tlv`` | string | Configures DCBx application priority TLVs advertisement | os9 | +| ``advertise.dcbx_appln_tlv_state`` | string: present,absent | Deletes DCBx application priority TLVs advertisement if set to absent | os9 | +| ``advertise.dot1_tlv`` | dictionary | Configures 802.1 TLVs advertisement (see ``dot1_tlv.*``) | os9 | +| ``dot1_tlv.port_tlv`` | dictionary | Configures 802.1 TLVs advertisement (see ``port_tlv.*``) | os9 | +| ``port_tlv.protocol_vlan_id`` | boolean | Configures 802.1 VLAN ID TLVs advertisement | os9 | +| ``port_tlv.port_vlan_id`` | boolean | Configures 802.1 VLAN ID TLVs advertisement | os9 | +| ``dot1_tlv.vlan_tlv`` | dictionary | Configures 802.1 VLAN TLVs advertisement (see ``vlan_tlv.*``) | os9 | +| ``vlan_tlv.vlan_range`` | string | Configures 802.1 VLAN name TLVs advertisement | os9 | +| ``advertise.dot3_tlv`` | dictionary | Configures 802.3 TLVs advertisement (see ``dot3_tlv.*``) | os9 | +| ``dot3_tlv.max_frame_size`` | boolean | Configures 802.3 maximum frame size TLVs advertisement | os9 | +| ``advertise.port_descriptor`` | boolean | Configures global port descriptor advertisement | os9 | +| ``advertise.management_tlv`` | string | Configures global management TLVs advertisement | os9 | +| ``advertise.management_tlv_state`` | string: absent,present | Deletes global TLVs advertisement if set to absent | os9 | +| ``advertise.med`` | dictionary | Configures MED TLVs advertisement (see ``med_tlv.*``) | , os9 | +| ``med.global_med`` | boolean | Configures global MED TLVs advertisement | os9 | +| ``med.application`` | list | Configures global MED TLVs advertisement for an application (see ``application.*``) | os9 | +| ``application.name`` | string | Configures the application name for MED TLVs advertisement | os9 | +| ``application.vlan_id`` | integer | Configures the VLAN ID for the application MED TLVs advertisement (1 to 4094) | os9 | +| ``application.priority_tagged`` | boolean | Configures priority tagged for the application MED TLVs advertisement; mutually exclusive with *application.vlan_id* | os9 | +| ``application.l2_priority`` | integer | Configures the L2 priority for the application MED TLVs advertisement (0 to 7) | os9 | +| ``application.code_point_value`` | integer | Configures differentiated services code point values for MED TLVs advertisement (0 to 63) | os9 | +| ``med.location_identification`` | list | Configures MED location identification TLVs advertisement (see ``location_identification.*``) | os9 | +| ``location_identification.loc_info`` | string | Configures location information for MED TLVs advertisement | os9 | +| ``location_identification.value`` | string | Configures location information values | os9 | +| ``location_identification.state`` | string: absent,present | Deletes the location information if set to absent | os9 | +| ``management_interface`` | dictionary | Configures LLDP on the management interface (see ``management_interface.*``) | os9 | +| ``management_interface.enable`` | boolean | Enables or disables LLDP on the management interface | os9 | +| ``management_interface.hello`` | integer | Configures LLDP hello interval on the management interface (5 to 180) | os9 | +| ``management_interface.mode`` | string: rx,tx | Configures LLDP mode on the management interface | os9 | +| ``management_interface.multiplier`` | integer | Configures LLDP multiplier on the management interface (2 to 10) | os9 | +| ``management_interface.advertise`` | dictionary | Configures TLV advertisement on the management interface (see ``advertise.*``) | os9 | +| ``advertise.port_descriptor`` | boolean | Configures port descriptor advertisement on the management interface | os9 | +| ``advertise.management_tlv`` | string | Configures management TLVs advertisement | os9 | +| ``advertise.management_tlv_state`` | string: absent,present | Deletes management TLVs advertisement if set to absent | os9 | +| ``local_interface`` | dictionary | Configures LLDP at the interface level (see ``local_interface.*``) | os9 | +| ``local_interface.`` | dictionary | Configures LLDP at the interface level (see ``.*``) | os9 | +| ``.state`` | string: absent,present | Deletes LLDP at the interface level if set to absent | os9 | +| ``.enable`` | boolean | Enables or disables LLDP at the interface level | os9 | +| ``.hello`` | integer | Configures LLDP hello interval at the interface level (5 to 180) | os9 | +| ``.mode`` | string: rx,tx | Configures LLDP mode configuration at the interface level | os9 | +| ``.multiplier`` | integer | Configures LLDP multiplier at the interface level (2 to 10) | os9 | +| ``.dcbx`` | dictionary | Configures DCBx parameters at the interface level (see ``dcbx.*``) | os9 | +| ``dcbx.version`` | string | Configures DCBx version at the interface level | os9 | +| ``dcbx.port_role`` | string | Configures DCBx port role at the interface level | os9 | +| ``.advertise`` | dictionary | Configures LLDP-MED TLV advertisement at the interface level (see ``advertise.*``) | os9 | +| ``advertise.dcbx_tlv`` | string | Configures DCBx TLVs advertisement at the interface level | os9 | +| ``advertise.dcbx_tlv_state`` | string: present,absent | Deletes interface level DCBx TLVs advertisement if set to absent | os9 | +| ``advertise.dcbx_appln_tlv`` | string | Configures DCBx application priority TLVs advertisement at the interface level | os9 | +| ``advertise.dcbx_appln_tlv_state`` | string: present,absent | Deletes interface level DCBx application priority TLVs advertisement if set to absent | os9 | +| ``advertise.dot1_tlv`` | dictionary | Configures 802.1 TLVs advertisement at the interface level (see ``dot1_tlv.*``) | os9 | +| ``dot1_tlv.port_tlv`` | dictionary | Configures 802.1 TLVs advertisement at the interface level (see ``port_tlv.*``) | os9 | +| ``port_tlv.protocol_vlan_id`` | boolean | Configures 802.1 VLAN ID TLVs advertisement at the interface level | os9 | +| ``port_tlv.port_vlan_id`` | boolean | Configures 802.1 VLAN ID TLVs advertisement at the interface level | os9 | +| ``dot1_tlv.vlan_tlv`` | dictionary | Configures 802.1 VLAN TLVs advertisement at the interface level (see ``vlan_tlv.*``) | os9 | +| ``vlan_tlv.vlan_range`` | string | Configures 802.1 VLAN name TLVs advertisement at the interface level | os9 | +| ``advertise.dot3_tlv`` | dictionary | Configures 802.3 TLVs advertisement at the interface level (see ``dot3_tlv.*``) | os9 | +| ``dot3_tlv.max_frame_size`` | boolean | Configures 802.3 maximum frame size TLVs advertisement at the interface level | os9 | +| ``advertise.port_descriptor`` | boolean | Configures port descriptor advertisement at the interface level | os9 | +| ``advertise.management_tlv`` | string | Configures TLVs advertisement at the interface level | os9 | +| ``advertise.management_tlv_state`` | string: absent,present | Deletes TLVs advertisement at the interface level if set to absent | os9 | +| ``advertise.med`` | dictionary | Configures MED TLVs advertisement at the interface level (see ``med_tlv.*``) | os9 | +| ``med.global_med`` | boolean | Configures MED TLVs advertisement at the interface level | os9 | +| ``med.application`` | list | Configures MED TLVs advertisement for the application at the interface level (see ``application.*``) | os9 | +| ``application.name`` | string | Configures the application name for MED TLVs advertisement | os9 | +| ``application.vlan_id`` | integer | Configures the VLAN ID for the application MED TLVs advertisement at the interface level (1 to 4094) | os9 | +| ``application.priority_tagged`` | boolean | Configures priority tagged for the application MED TLVs advertisement at the interface level; mutually exclusive with *application.vlan_id* | os9 | +| ``application.l2_priority`` | integer | Configures the L2 priority for the application MED TLVs advertisement at the interface level (0 to 7) | os9 | +| ``application.code_point_value`` | integer | Configures differentiated services code point value for MED TLVs advertisement at the interface level (0 to 63) | os9 | +| ``med.location_identification`` | list | Configures MED location identification TLVs advertisement at the interface level (see ``location_identification.*``) | os9 | +| ``location_identification.loc_info`` | string | Configures location information for MED TLVs advertisement at the interface level | os9 | +| ``location_identification.value`` | string | Configures the location information value for MED TLVs advertisement at the interface level | os9 | +| ``location_identification.state`` | string: absent,present | Deletes the interface level MED location information if set to absent | os9 | + + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_lldp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_lldp* role to configure protocol lldp. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_lldp* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_lldp: + global_lldp_state: present + enable: false + mode: rx + multiplier: 3 + fcoe_priority_bits: 3 + iscsi_priority_bits: 3 + hello: 6 + dcbx: + version: auto + management_interface: + hello: 7 + multiplier: 3 + mode: tx + enable: true + advertise: + port_descriptor: false + management_tlv: management-address system-capabilities + management_tlv_state: absent + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: absent + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + dot3_tlv: + max_frame_size: false + port_descriptor: false + management_tlv: management-address system-capabilities + management_tlv_state: absent + med: + global_med: true + application: + - name: "guest-voice" + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 + state: present + local_interface: + fortyGigE 1/3: + lldp_state: present + enable: false + mode: rx + multiplier: 3 + hello: 8 + dcbx: + version: auto + port_role: auto-upstream + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: present + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: absent + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + state: present + dot3_tlv: + max_frame_size: true + port_descriptor: true + management_tlv: management-address system-capabilities + management_tlv_state: absent + med: + application: + - name: guest-voice + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_lldp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_lldp/defaults/main.yml b/roles/os9_lldp/defaults/main.yml new file mode 100644 index 0000000..11d293a --- /dev/null +++ b/roles/os9_lldp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_lldp \ No newline at end of file diff --git a/roles/os9_lldp/handlers/main.yml b/roles/os9_lldp/handlers/main.yml new file mode 100644 index 0000000..38e013e --- /dev/null +++ b/roles/os9_lldp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_lldp \ No newline at end of file diff --git a/roles/os9_lldp/meta/main.yml b/roles/os9_lldp/meta/main.yml new file mode 100644 index 0000000..53c747a --- /dev/null +++ b/roles/os9_lldp/meta/main.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: > + The os9_lldp role facilitates the configuration of Link Layer Discovery Protocol(LLDP) attributes in devices + running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 + diff --git a/roles/os9_lldp/tasks/main.yml b/roles/os9_lldp/tasks/main.yml new file mode 100644 index 0000000..03e6108 --- /dev/null +++ b/roles/os9_lldp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating LLDP configuration for os9" + template: + src: os9_lldp.j2 + dest: "{{ build_dir }}/lldp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning LLDP configuration for os9" + os9_config: + src: os9_lldp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_lldp/templates/os9_lldp.j2 b/roles/os9_lldp/templates/os9_lldp.j2 new file mode 100644 index 0000000..7f53560 --- /dev/null +++ b/roles/os9_lldp/templates/os9_lldp.j2 @@ -0,0 +1,516 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################################### +Purpose: +Configure LLDP commands for os9 Devices. + +os9_lldp: + global_lldp_state: present + enable: false + mode: rx + multiplier: 3 + iscsi_priority_bits: 3 + fcoe_priority_bits: 3 + hello: 8 + dcbx: + version: auto + management_interface: + hello: 6 + multiplier: 3 + mode: tx + enable: true + advertise: + port_descriptor: false + management_tlv: management-address system-capabilities + management_tlv_state: present + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: present + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + state: present + dot3_tlv: + max_frame_size: true + port_descriptor: true + management_tlv: management-address system-capabilities + management_tlv_state: present + med: + application: + - name: guest-voice + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 + local_interface: + fortyGigE 1/3: + lldp_state: present + enable: false + mode: rx + multiplier: 3 + hello: 8 + dcbx: + version: auto + port_role: auto-upstream + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: present + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + state: present + dot3_tlv: + max_frame_size: true + port_descriptor: true + management_tlv: management-address system-capabilities + management_tlv_state: present + med: + application: + - name: guest-voice + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 + + +####################################################} +{% if os9_lldp is defined and os9_lldp %} + {% set global_state = [] %} + {% if global_state.append(True) %}{% endif %} + + {% for key in os9_lldp.keys() %} + {% set lldp_vars = os9_lldp[key] %} + {% if key == "global_lldp_state" and lldp_vars == "absent" %} +no protocol lldp + {% if global_state.insert(False,0) %}{% endif %} + {% endif %} + {% endfor %} + +{% if global_state[0] %} +protocol lldp +{% endif %} + +{% for key in os9_lldp.keys() %} +{% set lldp_vars = os9_lldp[key] %} +{% if global_state[0] %} +{% if key == "management_interface" %} + management-interface + {% if lldp_vars.hello is defined and lldp_vars.hello %} + hello {{ lldp_vars.hello }} + {% else %} + no hello + {% endif %} + {% if lldp_vars.enable is defined and lldp_vars.enable %} + no disable + {% else %} + disable + {% endif %} + {% if lldp_vars.mode is defined and lldp_vars.mode %} + mode {{ lldp_vars.mode }} + {% else %} + no mode + {% endif %} + {% if lldp_vars.multiplier is defined and lldp_vars.multiplier %} + multiplier {{ lldp_vars.multiplier }} + {% else %} + no multiplier + {% endif %} + {% if lldp_vars.advertise is defined and lldp_vars.advertise %} + {% if lldp_vars.advertise.port_descriptor is defined %} + {% if lldp_vars.advertise.port_descriptor %} + advertise interface-port-desc + {% else %} + no advertise interface-port-desc + {% endif %} + {% endif %} + {% if lldp_vars.advertise.management_tlv is defined and lldp_vars.advertise.management_tlv %} + {% if lldp_vars.advertise.management_tlv_state is defined and lldp_vars.advertise.management_tlv_state == "absent" %} + no advertise management-tlv {{ lldp_vars.advertise.management_tlv }} + {% else %} + advertise management-tlv {{ lldp_vars.advertise.management_tlv }} + {% endif %} + {% endif %} + {% endif %} +{% endif %} +{% if key == "enable" %} + {% if lldp_vars %} + no disable + {% else %} + disable + {% endif %} +{% endif %} +{% if key == "fcoe_priority_bits" %} + {% if lldp_vars %} + fcoe priority-bits {{ lldp_vars }} + {% else %} + no fcoe priority-bits + {% endif %} +{% endif %} +{% if key == "hello" %} + {% if lldp_vars %} + hello {{ lldp_vars }} + {% else %} + no hello + {% endif %} +{% endif %} +{% if key == "mode" %} + {% if lldp_vars %} + mode {{ lldp_vars }} + {% else %} + no mode + {% endif %} +{% endif %} +{% if key == "multiplier" %} + {% if lldp_vars %} + multiplier {{ lldp_vars }} + {% else %} + no multiplier + {% endif %} +{% endif %} +{% if key == "iscsi_priority_bits" %} + {% if lldp_vars %} + iscsi priority-bits {{ lldp_vars }} + {% else %} + no iscsi priority-bits + {% endif %} +{% endif %} +{% if key == "dcbx" %} + {% if lldp_vars.version is defined and lldp_vars.version %} + dcbx version {{ lldp_vars.version }} + {% else %} + no dcbx version + {% endif %} +{% endif %} +{% if key == "advertise" %} +{% if lldp_vars.management_tlv is defined and lldp_vars.management_tlv %} + {% if lldp_vars.management_tlv_state is defined and lldp_vars.management_tlv_state == "absent" %} + no advertise management-tlv {{ lldp_vars.management_tlv }} + {% else %} + advertise management-tlv {{ lldp_vars.management_tlv }} + {% endif %} +{% endif %} + +{% if lldp_vars.port_descriptor is defined %} + {% if lldp_vars.port_descriptor %} + advertise interface-port-desc + {% else %} + no advertise interface-port-desc + {% endif %} +{% endif %} + +{% if lldp_vars.med is defined and lldp_vars.med %} + {% for med in lldp_vars.med.keys() %} + {% set med_vars = lldp_vars.med[med] %} + {% if med == "global_med" %} + {% if med_vars %} + advertise med + {% else %} + no advertise med + {% endif %} + {% endif %} + {% if med == "location_identification" %} + {% for loc in med_vars %} + {% if loc.loc_info is defined and loc.loc_info %} + {% if loc.value is defined and loc.value %} + {% if loc.state is defined and loc.state == "absent" %} + no advertise med location-identification {{ loc.loc_info }} {{ loc.value }} + {% else %} + advertise med location-identification {{ loc.loc_info }} {{ loc.value }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if med == "application" %} + {% for app in med_vars %} + {% if app.name is defined and app.name %} + {% if app.vlan_id is defined and app.vlan_id %} + {% set vlan_or_tag = app.vlan_id %} + {% elif app.priority_tagged is defined and app.priority_tagged %} + {% set vlan_or_tag = "priority-tagged" %} + {% endif %} + {% if vlan_or_tag is defined and vlan_or_tag %} + {% if app.l2_priority is defined and app.l2_priority %} + {% if app.code_point_value is defined and app.code_point_value %} + {% if app.state is defined and app.state == "absent" %} + no advertise med {{ app.name }} {{ vlan_or_tag }} {{ app.l2_priority }} {{ app.code_point_value }} + {% else %} + advertise med {{ app.name }} {{ vlan_or_tag }} {{ app.l2_priority }} {{ app.code_point_value }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} +{% endif %} + +{% if lldp_vars.dcbx_tlv is defined and lldp_vars.dcbx_tlv %} + {% if lldp_vars.dcbx_tlv_state is defined and lldp_vars.dcbx_tlv_state == "absent" %} + no advertise dcbx-tlv {{ lldp_vars.dcbx_tlv }} + {% else %} + advertise dcbx-tlv {{ lldp_vars.dcbx_tlv }} + {% endif %} +{% endif %} + +{% if lldp_vars.dcbx_appln_tlv is defined and lldp_vars.dcbx_appln_tlv %} + {% if lldp_vars.dcbx_appln_tlv_state is defined and lldp_vars.dcbx_appln_tlv_state == "absent" %} + no advertise dcbx-appln-tlv {{ lldp_vars.dcbx_appln_tlv }} + {% else %} + advertise dcbx-appln-tlv {{ lldp_vars.dcbx_appln_tlv }} + {% endif %} +{% endif %} + +{% if lldp_vars.dot3_tlv is defined and lldp_vars.dot3_tlv %} + {% for dot3 in lldp_vars.dot3_tlv.keys() %} + {% set dot3_vars = lldp_vars.dot3_tlv[dot3] %} + {% if dot3 == "max_frame_size" %} + {% if dot3_vars %} + advertise dot3-tlv max-frame-size + {% else %} + no advertise dot3-tlv max-frame-size + {% endif %} + {% endif %} + {% endfor %} +{% endif %} + +{% if lldp_vars.dot1_tlv is defined and lldp_vars.dot1_tlv %} + {% for dot1 in lldp_vars.dot1_tlv.keys() %} + {% set dot1_vars = lldp_vars.dot1_tlv[dot1] %} + {% if dot1 == "port_tlv" %} + {% if dot1_vars.protocol_vlan_id is defined and dot1_vars.protocol_vlan_id %} + {% if dot1_vars.port_vlan_id is defined %} + {% if dot1_vars.port_vlan_id %} + advertise dot1-tlv port-protocol-vlan-id port-vlan-id + {% else %} + advertise dot1-tlv port-protocol-vlan-id + no advertise dot1-tlv port-vlan-id + {% endif %} + {% else %} + advertise dot1-tlv port-protocol-vlan-id + {% endif %} + {% else %} + {% if not dot1_vars.protocol_vlan_id %} + no advertise dot1-tlv port-protocol-vlan-id + {% endif %} + {% if dot1_vars.port_vlan_id is defined %} + {% if dot1_vars.port_vlan_id %} + advertise dot1-tlv port-vlan-id + {% else %} + no advertise dot1-tlv port-vlan-id + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if dot1 == "vlan_tlv" %} + {% if dot1_vars.vlan_range is defined and dot1_vars.vlan_range %} + {% if dot1_vars.state is defined and dot1_vars.state == "absent" %} + no advertise dot1-tlv vlan-name vlan-id {{ dot1_vars.vlan_range }} + {% else %} + advertise dot1-tlv vlan-name vlan-id {{ dot1_vars.vlan_range }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if os9_lldp is defined and os9_lldp %} +{% for key in os9_lldp.keys() %} +{% set lldp_vars = os9_lldp[key] %} +{% if key == "local_interface" %} + {% for intf in lldp_vars.keys() %} + {% set intf_vars = lldp_vars[intf] %} +interface {{ intf }} + {% if intf_vars.lldp_state is defined and intf_vars.lldp_state == "absent" %} + no protocol lldp + {% else %} + protocol lldp + {% if intf_vars.hello is defined and intf_vars.hello %} + hello {{ intf_vars.hello }} + {% else %} + no hello + {% endif %} + {% if intf_vars.enable is defined and intf_vars.enable %} + no disable + {% else %} + disable + {% endif %} + {% if intf_vars.mode is defined and intf_vars.mode %} + mode {{ intf_vars.mode }} + {% else %} + no mode + {% endif %} + {% if intf_vars.multiplier is defined and intf_vars.multiplier %} + multiplier {{ intf_vars.multiplier }} + {% else %} + no multiplier + {% endif %} + {% if intf_vars.dcbx is defined and intf_vars.dcbx %} + {% if intf_vars.dcbx.version is defined and intf_vars.dcbx.version %} + dcbx version {{ intf_vars.dcbx.version }} + {% else %} + no dcbx version + {% endif %} + {% endif %} + {% if intf_vars.advertise is defined and intf_vars.advertise %} + {% if intf_vars.advertise.port_descriptor is defined %} + {% if intf_vars.advertise.port_descriptor %} + advertise interface-port-desc + {% else %} + no advertise interface-port-desc + {% endif %} + {% endif %} + {% if intf_vars.advertise.management_tlv is defined and intf_vars.advertise.management_tlv %} + {% if intf_vars.advertise.management_tlv_state is defined and intf_vars.advertise.management_tlv_state == "ab +sent" %} + no advertise management-tlv {{ intf_vars.advertise.management_tlv }} + {% else %} + advertise management-tlv {{ intf_vars.advertise.management_tlv }} + {% endif %} + {% endif %} + {% if intf_vars.advertise.med is defined and intf_vars.advertise.med %} + {% for med in intf_vars.advertise.med.keys() %} + {% set med_vars = intf_vars.advertise.med[med] %} + {% if med == "global_med" %} + {% if med_vars %} + advertise med + {% else %} + no advertise med + {% endif %} + {% endif %} + {% if med == "location_identification" %} + {% for loc in med_vars %} + {% if loc.loc_info is defined and loc.loc_info %} + {% if loc.value is defined and loc.value %} + {% if loc.state is defined and loc.state == "absent" %} + no advertise med location-identification {{ loc.loc_info }} {{ loc.value }} + {% else %} + advertise med location-identification {{ loc.loc_info }} {{ loc.value }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if med == "application" %} + {% for app in med_vars %} + {% if app.name is defined and app.name %} + {% if app.vlan_id is defined and app.vlan_id %} + {% set vlan_or_tag = app.vlan_id %} + {% elif app.priority_tagged is defined and app.priority_tagged %} + {% set vlan_or_tag = "priority-tagged" %} + {% endif %} + {% if vlan_or_tag is defined and vlan_or_tag %} + {% if app.l2_priority is defined and app.l2_priority %} + {% if app.code_point_value is defined and app.code_point_value %} + {% if app.state is defined and app.state == "absent" %} + no advertise med {{ app.name }} {{ vlan_or_tag }} {{ app.l2_priority }} {{ app.code_point_value }} + {% else %} + advertise med {{ app.name }} {{ vlan_or_tag }} {{ app.l2_priority }} {{ app.code_point_value }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + + {% if intf_vars.advertise.dcbx_tlv is defined and intf_vars.advertise.dcbx_tlv %} + {% if intf_vars.advertise.dcbx_tlv_state is defined and intf_vars.advertise.dcbx_tlv_state == "absent" %} + no advertise dcbx-tlv {{ intf_vars.advertise.dcbx_tlv }} + {% else %} + advertise dcbx-tlv {{ intf_vars.advertise.dcbx_tlv }} + {% endif %} + {% endif %} + + {% if intf_vars.advertise.dcbx_appln_tlv is defined and intf_vars.advertise.dcbx_appln_tlv %} + {% if intf_vars.advertise.dcbx_appln_tlv_state is defined and intf_vars.advertise.dcbx_appln_tlv_state == "absent" %} + no advertise dcbx-appln-tlv {{ intf_vars.advertise.dcbx_appln_tlv }} + {% else %} + advertise dcbx-appln-tlv {{ intf_vars.advertise.dcbx_appln_tlv }} + {% endif %} + {% endif %} + + {% if intf_vars.advertise.dot3_tlv is defined and intf_vars.advertise.dot3_tlv %} + {% for dot3 in intf_vars.advertise.dot3_tlv.keys() %} + {% set dot3_vars = intf_vars.advertise.dot3_tlv[dot3] %} + {% if dot3 == "max_frame_size" %} + {% if dot3_vars %} + advertise dot3-tlv max-frame-size + {% else %} + no advertise dot3-tlv max-frame-size + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if intf_vars.advertise.dot1_tlv is defined and intf_vars.advertise.dot1_tlv %} + {% for dot1 in intf_vars.advertise.dot1_tlv.keys() %} + {% set dot1_vars = intf_vars.advertise.dot1_tlv[dot1] %} + {% if dot1 == "port_tlv" %} + {% if dot1_vars.protocol_vlan_id is defined and dot1_vars.protocol_vlan_id %} + {% if dot1_vars.port_vlan_id is defined %} + {% if dot1_vars.port_vlan_id %} + advertise dot1-tlv port-protocol-vlan-id port-vlan-id + {% else %} + advertise dot1-tlv port-protocol-vlan-id + no advertise dot1-tlv port-vlan-id + {% endif %} + {% else %} + advertise dot1-tlv port-protocol-vlan-id + {% endif %} + {% else %} + {% if not dot1_vars.protocol_vlan_id %} + no advertise dot1-tlv port-protocol-vlan-id + {% endif %} + {% if dot1_vars.port_vlan_id is defined %} + {% if dot1_vars.port_vlan_id %} + advertise dot1-tlv port-vlan-id + {% else %} + no advertise dot1-tlv port-vlan-id + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if dot1 == "vlan_tlv" %} + {% if dot1_vars.vlan_range is defined and dot1_vars.vlan_range %} + {% if dot1_vars.state is defined and dot1_vars.state == "absent" %} + no advertise dot1-tlv vlan-name vlan-id {{ dot1_vars.vlan_range }} + {% else %} + advertise dot1-tlv vlan-name vlan-id {{ dot1_vars.vlan_range }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_lldp/tests/inventory.yaml b/roles/os9_lldp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_lldp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_lldp/tests/main.os9.yaml b/roles/os9_lldp/tests/main.os9.yaml new file mode 100644 index 0000000..ab40de8 --- /dev/null +++ b/roles/os9_lldp/tests/main.os9.yaml @@ -0,0 +1,94 @@ +--- +# vars file for dellemc.os9.os9_lldp, +# below gives a sample configuration +# Sample variables for OS9 device +os9_lldp: + global_lldp_state: present + enable: false + mode: rx + multiplier: 3 + fcoe_priority_bits: 3 + iscsi_priority_bits: 3 + hello: 6 + dcbx: + version: auto + management_interface: + hello: 7 + multiplier: 3 + mode: tx + enable: true + advertise: + port_descriptor: false + management_tlv: management-address system-capabilities + management_tlv_state: absent + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: absent + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + dot3_tlv: + max_frame_size: false + port_descriptor: false + management_tlv: management-address system-capabilities system-name + management_tlv_state: present + med: + global_med: true + application: + - name: "guest-voice" + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 + state: present + local_interface: + fortyGigE 1/3: + lldp_state: present + enable: false + mode: rx + multiplier: 3 + hello: 8 + dcbx: + version: auto + port_role: auto-upstream + advertise: + dcbx_tlv: pfc + dcbx_tlv_state: present + dcbx_appln_tlv: fcoe + dcbx_appln_tlv_state: + dot1_tlv: + port_tlv: + protocol_vlan_id: true + port_vlan_id: true + vlan_tlv: + vlan_range: 2-4 + state: present + dot3_tlv: + max_frame_size: true + port_descriptor: true + management_tlv: management-address system-capabilities + management_tlv_state: present + med: + application: + - name: guest-voice + vlan_id: 2 + l2_priority: 3 + code_point_value: 4 + - name: voice + priority_tagged: true + l2_priority: 3 + code_point_value: 4 + location_identification: + - loc_info: ecs-elin + value: 12345678911 \ No newline at end of file diff --git a/roles/os9_lldp/tests/test.yaml b/roles/os9_lldp/tests/test.yaml new file mode 100644 index 0000000..4990110 --- /dev/null +++ b/roles/os9_lldp/tests/test.yaml @@ -0,0 +1,6 @@ + +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_lldp \ No newline at end of file diff --git a/roles/os9_lldp/vars/main.yml b/roles/os9_lldp/vars/main.yml new file mode 100644 index 0000000..b10424e --- /dev/null +++ b/roles/os9_lldp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_lldp \ No newline at end of file diff --git a/roles/os9_logging/LICENSE b/roles/os9_logging/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_logging/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_logging/README.md b/roles/os9_logging/README.md new file mode 100644 index 0000000..ac2d70b --- /dev/null +++ b/roles/os9_logging/README.md @@ -0,0 +1,151 @@ +Logging role +============ + +This role facilitates the configuration of global logging attributes, and it supports the configuration of logging servers. This role is abstracted for Dell EMC platforms running OS9. + +The Logging role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If the *os9_cfg_generate* variable is set to true, it generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_logging keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``logging`` | list | Configures the logging server (see ``logging.*``) | os9 | +| ``logging.ip`` | string (required) | Configures the IPv4 address for the logging server (A.B.C.D format) | os9 | +| ``logging.secure_port`` | integer | Specifies log messages over the TLS port | os9 | +| ``logging.tcp_port`` | integer | Specifies log messages over the TCP port if *secure_port* is not defined | os9 | +| ``logging.udp_port`` | integer | Specifies log messages over the UDP port if both TCP and the secure port key are not defined | os9 | +| ``logging.vrf`` | dict | Specifies a VRF instance to be used to reach the host | os9 | +| ``logging.vrf.name`` | string | Specifies the VRF name | os9 | +| ``logging.vrf.secure_port`` | integer | Specifies log messages over the TLS port | os9 | +| ``logging.vrf.tcp_port`` | integer | Specifies log messages over the TCP port if *secure_port key* is not defined | os9 | +| ``logging.vrf.udp_port`` | integer | Specifies log messages over the UDP port if both TCP and *secure_port_key* is not defined | os9 | +| ``logging.vrf.state`` | string: absent,present\* | Deletes VRF instance of the logging server if set to absent | os9 | +| ``logging.state`` | string: absent,present\* | Deletes the logging server if set to absent | os9 | +| ``buffer`` | integer | Specifies the buffered logging severity level (0 to 7) | os9 | +| ``console_level`` | integer | Configures the console logging level (0 to 7) | os9 | +| ``trap_level`` | integer | Configures the syslog server severity level (0 to 7) | os9| +| ``syslog_version`` | integer | Configures the syslog version (0/1) | os9 | +| ``monitor`` | integer | Configures the terminal line logging level (0 to 7) | os9| +| ``history`` | integer | Configures the syslog history table (0 to 7) | os9 | +| ``history_size`` | integer | Specifies the history table size | os9 | +| ``on`` | boolean | Enables logging to all supported destinations if set to true | os9 | +| ``extended`` | boolean | Enables extended logging if set to true | os9 | +| ``coredump`` | dict | Configures coredump logging | os9 | +| ``coredump.server`` | dict | Specifies all server details | os9 | +| ``coredump.server.server_ip`` | string (required) | Specifies the IPv4/IPv6 address of the logging server | os9 | +| ``coredump.server.username`` | string | Specifies the username to be configured | os9 | +| ``coredump.server.password`` | string | Specifies the password to be configured | os9 | +| ``coredump.server.state`` | string: present,absent\* | Deletes the coredump server if set to absent | os9 | +| ``coredump.stackunit`` |dict | Specifies details for enabling a coredump on the stack-unit | os9 | +| ``coredump.stackunit.all`` | boolean | Enables a coredump on all stack-units | os9 | +| ``coredump.stackunit.unit_num`` | integer | Specifies the stack-unit number (0 to 5) | os9 | +| ``coredump.stackunit.state`` | string: present,absent\*| Deletes the stack-unit coredump if set to absent | os9 | +| ``source_interface`` | string | Configures the source interface for logging | os9 | + +> **NOTE**: Asterisk (_*_) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_logging* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_logging* role to completely set up logging servers. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. + +**Sample hosts file** + + leaf1 ansible_host= + +#### Sample host_vars/leaf1 + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_logging: + logging: + - ip : 1.1.1.1 + state: present + - ip: 2.2.2.2 + secure_port: 1025 + tcp_port: 1024 + udp_port: 2000 + state: present + - ip: 3.3.3.3 + vrf: + name: test + secure_port: 1024 + tcp_port: 1025 + udp_port: 2000 + state: present + secure_port: 1025 + tcp_port: 2000 + udp_port: 1025 + state: present + buffer: 5 + console_level: 7 + trap_level: 5 + syslog_version: 5 + history: 4 + history_size: 3 + monitor: 5 + on: true + extended: true + coredump: + server: + server_ip: 2.2.2.2 + username: u1 + password: pwd + state: present + stackunit: + all: true + unit_num: 5 + state: present + source_interface: "fortyGigE 1/9" + +**Simple playbook to setup logging - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_logging + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_logging/defaults/main.yml b/roles/os9_logging/defaults/main.yml new file mode 100644 index 0000000..ef0a1c9 --- /dev/null +++ b/roles/os9_logging/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_logging \ No newline at end of file diff --git a/roles/os9_logging/handlers/main.yml b/roles/os9_logging/handlers/main.yml new file mode 100644 index 0000000..36b3d65 --- /dev/null +++ b/roles/os9_logging/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_logging \ No newline at end of file diff --git a/roles/os9_logging/meta/main.yml b/roles/os9_logging/meta/main.yml new file mode 100644 index 0000000..fd84cab --- /dev/null +++ b/roles/os9_logging/meta/main.yml @@ -0,0 +1,19 @@ + +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_logging role facilitates the configuration of logging attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_logging/tasks/main.yml b/roles/os9_logging/tasks/main.yml new file mode 100644 index 0000000..797c89d --- /dev/null +++ b/roles/os9_logging/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating logging configuration for os9" + template: + src: os9_logging.j2 + dest: "{{ build_dir }}/logging9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning logging configuration for os9" + os9_config: + src: os9_logging.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_logging/templates/os9_logging.j2 b/roles/os9_logging/templates/os9_logging.j2 new file mode 100644 index 0000000..d932b3c --- /dev/null +++ b/roles/os9_logging/templates/os9_logging.j2 @@ -0,0 +1,198 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure logging commands for os9 Devices +os9_logging: + logging: + - ip : 1.1.1.1 + state: present + - ip: 2.2.2.2 + secure_port: 1025 + tcp_port: 1024 + udp_port: 2000 + state: present + - ip: 3.3.3.3 + vrf: + name: test + secure_port: 1024 + tcp_port: 1025 + udp_port: 2000 + state: present + secure_port: 1025 + tcp_port: 2000 + udp_port: 1025 + state: present + buffer: 6 + console_level: 7 + trap_level: 5 + syslog_version: 5 + history: 4 + history_size: 3 + monitor: 5 + on: true + extended: true + coredump: + server: + server_ip: 2.2.2.2 + username: u1 + password: pwd + state: present + stackunit: + all: true + unit_num: 5 + state: present + source_interface: "fortyGigE 1/3" +###################################################} +{% if os9_logging is defined and os9_logging %} +{% for key,value in os9_logging.items() %} + {% if key == "buffer" %} + {% if value %} +logging buffered {{ value }} + {% else %} +no logging buffered + {% endif %} + + {% elif key == "console" %} + {% if value %} +logging console {{ value }} + {% else %} +no logging console + {% endif %} + + {% elif key == "monitor" %} + {% if value %} +logging monitor {{ value }} + {% else %} +no logging monitor + {% endif %} + + {% elif key == "source_interface" %} + {% if value %} +logging source-interface {{ value }} + {% else %} +no logging source-interface + {% endif %} + + {% elif key == "version" %} + {% if value %} +logging version {{ value }} + {% else %} +no logging version + {% endif %} + + {% elif key == "history" %} + {% if value %} +logging history {{ value }} + {% else %} +no logging history + {% endif %} + + {% elif key == "history_size" %} + {% if value %} +logging history size {{ value }} + {% else %} +no logging history size + {% endif %} + + {% elif key == "trap" %} + {% if value %} +logging trap {{ value }} + {% else %} +no logging trap + {% endif %} + + {% elif key == "extended" %} + {% if value %} +logging extended + {% else %} +no logging extended + {% endif %} + + {% elif key == "on" %} + {% if value %} +logging on + {% else %} +no logging on + {% endif %} + + {% elif key == "logging" %} + {% if value %} + {% for item in value %} + {% if item.ip is defined and item.ip %} + {% if item.vrf is defined and item.vrf %} + {% if item.vrf.name is defined and item.vrf.name %} + {% if item.vrf.state is defined and item.vrf.state == "absent" %} + {% if item.vrf.secure_port is defined and item.vrf.secure_port %} +no logging {{ item.ip }} vrf {{ item.vrf.name }} secure {{ item.vrf.secure_port }} + {% elif item.vrf.tcp_port is defined and item.vrf.tcp_port %} +no logging {{ item.ip }} vrf {{ item.vrf.name }} tcp {{ item.vrf.tcp_port }} + {% elif item.vrf.udp_port is defined and item.vrf.udp_port %} +no logging {{ item.ip }} vrf {{ item.vrf.name }} udp {{ item.vrf.udp_port }} + {% endif %} + {% else %} + {% if item.vrf.secure_port is defined and item.vrf.secure_port %} +logging {{ item.ip }} vrf {{ item.vrf.name }} secure {{ item.vrf.secure_port }} + {% elif item.vrf.tcp_port is defined and item.vrf.tcp_port %} +logging {{ item.ip }} vrf {{ item.vrf.name }} tcp {{ item.vrf.tcp_port }} + {% elif item.vrf.udp_port is defined and item.vrf.udp_port %} +logging {{ item.ip }} vrf {{ item.vrf.name }} udp {{ item.vrf.udp_port }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if item.state is defined and item.state == "absent" %} + {% if item.secure_port is defined and item.secure_port %} +no logging {{ item.ip }} secure {{ item.secure_port }} + {% elif item.tcp_port is defined and item.tcp_port %} +no logging {{ item.ip }} tcp {{ item.tcp_port }} + {% elif item.udp_port is defined and item.udp_port %} +no logging {{ item.ip }} udp {{ item.udp_port }} + {% else %} +no logging {{ item.ip }} + {% endif %} + {% else %} + {% if item.secure_port is defined and item.secure_port %} +logging {{ item.ip }} secure {{ item.secure_port }} + {% elif item.tcp_port is defined and item.tcp_port %} +logging {{ item.ip }} tcp {{ item.tcp_port }} + {% elif item.udp_port is defined and item.udp_port %} +logging {{ item.ip }} udp {{ item.udp_port }} + {% else %} +logging {{ item.ip }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "coredump" %} + {% if value %} + {% if value.server is defined and value.server %} + {% if value.server.server_ip is defined and value.server.server_ip %} + {% if value.server.state is defined and value.server.state == "absent" %} +no logging coredump server {{ value.server.server_ip }}] + {% else %} + {% if value.server.username is defined and value.server.username and value.server.password is defined and value.server.password %} +logging coredump server {{ value.server.server_ip }} username {{ value.server.username }} password {{ value.server.password }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if value.stackunit is defined and value.stackunit %} + {% if value.stackunit.all is defined and value.stackunit.all %} + {% set my_str = "all " %} + {% else %} + {% if value.stackunit.unit_num is defined and value.stackunit.unit_num %} + {% set my_str = value.stackunit.unit_num|string %} + {% endif %} + {% endif %} + {% if value.stackunit.state is defined and value.stackunit.state == "absent" %} +no logging coredump stack-unit {{ my_str }} + {% else %} +logging coredump stack-unit {{ my_str }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_logging/tests/inventory.yaml b/roles/os9_logging/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_logging/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_logging/tests/main.os9.yaml b/roles/os9_logging/tests/main.os9.yaml new file mode 100644 index 0000000..b002d6e --- /dev/null +++ b/roles/os9_logging/tests/main.os9.yaml @@ -0,0 +1,44 @@ +--- +# vars file for dellemc.os9.os9_logging, +# below gives a sample configuration +# Sample variables for OS9 device +os9_logging: + logging: + - ip: 1.1.1.1 + state: present + - ip: 2.2.2.2 + secure_port: 1025 + tcp_port: 1024 + udp_port: 2000 + state: present + - ip: 3.3.3.3 + vrf: + name: test + secure_port: 1024 + tcp_port: 1025 + udp_port: 2000 + state: present + secure_port: 1025 + tcp_port: 2000 + udp_port: 1025 + state: present + buffer: 6 + console_level: 7 + trap_level: 5 + syslog_version: 5 + history: 4 + history_size: 3 + monitor: 5 + on: true + extended: true + coredump: + server: + server_ip: 2.2.2.2 + username: u1 + password: pwd + state: present + stackunit: + all: true + unit_num: 5 + state: present + source_interface: "fortyGigE 1/9" \ No newline at end of file diff --git a/roles/os9_logging/tests/test.yaml b/roles/os9_logging/tests/test.yaml new file mode 100644 index 0000000..3f87d4c --- /dev/null +++ b/roles/os9_logging/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_logging \ No newline at end of file diff --git a/roles/os9_logging/vars/main.yml b/roles/os9_logging/vars/main.yml new file mode 100644 index 0000000..bc9f7c3 --- /dev/null +++ b/roles/os9_logging/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_logging \ No newline at end of file diff --git a/roles/os9_ntp/LICENSE b/roles/os9_ntp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_ntp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_ntp/README.md b/roles/os9_ntp/README.md new file mode 100644 index 0000000..3d5e545 --- /dev/null +++ b/roles/os9_ntp/README.md @@ -0,0 +1,103 @@ +NTP role +======== + +This role facilitates the configuration of network time protocol (NTP) attributes. This role is abstracted for Dell EMC platforms running os9. It specifically enables configuration of NTP server for OS9. + +The NTP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_ntp keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``server`` | list | Configures the NTP server (see ``server.*``) | os9 | +| ``server.ip`` | string (required) | Configures an IPv4 address for the NTP server (A.B.C.D format) | os9 | +| ``server.vrf`` | list | Configures the NTP server for VRF instance; list item contains the names of the VRF instance | os9 | +| ``server.state`` | string: absent,present\* | Deletes the NTP server if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-------------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_ntp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_ntp* role to set the NTP server, source ip, authentication and broadcast service. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. When the *os9_cfg_generate* variable is set to true, it generates the configuration commands as a .part file in *build_dir* path. By default it is set to false. The example writes a simple playbook that only references the *os9_ntp* role. + +By including the role, you automatically get access to all of the tasks to configure NTP attributes. The sample *host_vars* is for os9. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + host: leaf1 + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_ntp: + source: ethernet 1/1/2 + master: 5 + authenticate: true + authentication_key: + - key_num: 123 + key_string_type: 7 + key_string: test + state: present + trusted_key: + - key_num: 1323 + state: present + server: + - ip: 2.2.2.2 + key: 345 + prefer: true + state: present + intf: + ethernet 1/1/2: + disable: true + broadcast: true + +**Simple playbook to setup NTP - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_ntp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_ntp/defaults/main.yml b/roles/os9_ntp/defaults/main.yml new file mode 100644 index 0000000..835ccd0 --- /dev/null +++ b/roles/os9_ntp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_ntp \ No newline at end of file diff --git a/roles/os9_ntp/handlers/main.yml b/roles/os9_ntp/handlers/main.yml new file mode 100644 index 0000000..f8519dd --- /dev/null +++ b/roles/os9_ntp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_ntp \ No newline at end of file diff --git a/roles/os9_ntp/meta/main.yml b/roles/os9_ntp/meta/main.yml new file mode 100644 index 0000000..1a5980b --- /dev/null +++ b/roles/os9_ntp/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_ntp role facilitates the configuration of NTP attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_ntp/tasks/main.yml b/roles/os9_ntp/tasks/main.yml new file mode 100644 index 0000000..c22230b --- /dev/null +++ b/roles/os9_ntp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating NTP configuration for os9" + template: + src: os9_ntp.j2 + dest: "{{ build_dir }}/ntp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning NTP configuration for os9" + os9_config: + src: os9_ntp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_ntp/templates/os9_ntp.j2 b/roles/os9_ntp/templates/os9_ntp.j2 new file mode 100644 index 0000000..be4536c --- /dev/null +++ b/roles/os9_ntp/templates/os9_ntp.j2 @@ -0,0 +1,41 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure NTP commands for os9 Devices +os9_ntp: + server: + - ip: 2.2.2.2 + vrf: + - test + - management + state: present +###################################################} +{% if os9_ntp is defined and os9_ntp %} + +{% for key,value in os9_ntp.items() %} + {% if key == "server" and value %} + {% for item in value %} + {% if item.ip is defined and item.ip %} + {% if item.state is defined and item.state == "absent" %} + {% if item.vrf is defined and item.vrf %} + {% for vrf_name in item.vrf %} +no ntp server vrf {{ vrf_name }} {{ item.ip }} + {% endfor %} + {% else %} +no ntp server {{ item.ip }} + {% endif %} + {% else %} + {% if item.vrf is defined and item.vrf %} + {% for vrf_name in item.vrf %} +ntp server vrf {{ vrf_name }} {{ item.ip }} + {% endfor %} + {% else %} +ntp server {{ item.ip }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_ntp/tests/inventory.yaml b/roles/os9_ntp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_ntp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_ntp/tests/main.os9.yaml b/roles/os9_ntp/tests/main.os9.yaml new file mode 100644 index 0000000..f5f4680 --- /dev/null +++ b/roles/os9_ntp/tests/main.os9.yaml @@ -0,0 +1,11 @@ +--- +# vars file for +# below gives a sample configuration +# Sample variables for OS9 device +os9_ntp: + server: + - ip: 2.2.2.2 + vrf: + - test + - tes + state: present \ No newline at end of file diff --git a/roles/os9_ntp/tests/test.yaml b/roles/os9_ntp/tests/test.yaml new file mode 100644 index 0000000..0e636d6 --- /dev/null +++ b/roles/os9_ntp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + connection: network_cli + roles: + - dellemc.os9.os9_ntp \ No newline at end of file diff --git a/roles/os9_ntp/vars/main.yml b/roles/os9_ntp/vars/main.yml new file mode 100644 index 0000000..7b69f09 --- /dev/null +++ b/roles/os9_ntp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_ntp \ No newline at end of file diff --git a/roles/os9_prefix_list/LICENSE b/roles/os9_prefix_list/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_prefix_list/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_prefix_list/README.md b/roles/os9_prefix_list/README.md new file mode 100644 index 0000000..92b211d --- /dev/null +++ b/roles/os9_prefix_list/README.md @@ -0,0 +1,115 @@ +Prefix-list role +================ + +This role facilitates the configuration of a prefix-list. It supports the configuration of an IP prefix-list, and assigns the prefix-list to line terminals. This role is abstracted for Dell EMC platforms running OS9. + +The prefix-list role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. +- If *os9_cfg_generate* set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_prefix_list keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``type`` | string (required): ipv4,ipv6 | Configures an L3 (IPv4/IPv6) prefix-list | os9 | +| ``name`` | string (required) | Configures the prefix-list name | os9 | +| ``description`` | string | Configures the prefix-list description | os9 | +| ``entries`` | list | Configures rules in the prefix-list (see ``seqlist.*``) | os9 | +| ``entries.number`` | int (required) | Specifies the sequence number of the prefix-list rule | os9 | +| ``entries.permit`` | boolean (required): true,false | Specifies the rule to permit packets if set to true, and specifies to reject packets if set to false | os9 | +| ``entries.net_num`` | string (required) | Specifies the network number | os9 | +| ``entries.mask`` | string (required) | Specifies the mask | os9 | +| ``entries.condition_list`` | list | Configures conditions to filter packets (see ``condition_list.*``)| os9 | +| ``condition_list.condition`` | list | Specifies the condition to filter packets from the source address | os9 | +| ``condition_list.prelen`` | string (required) | Specifies the allowed prefix length | os9 | +| ``entries.state`` | string: absent,present\* | Deletes the rule from the prefix-list if set to absent | os9 | +| ``state`` | string: absent,present\* | Deletes the prefix-list if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_prefix_list* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_prefix_list* role to configure prefix_list for both IPv4 and IPv6. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_prefix_list* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_prefix_list: + - type: ipv4 + name: spine-leaf + description: Redistribute loopback and leaf networks + entries: + - number: 5 + permit: true + net_num: 10.0.0.0 + mask: 23 + condition_list: + - condition: ge + prelen: 32 + - number: 19 + permit: true + net_num: 20.0.0.0 + mask: 16 + condition_list: + - condition: ge + prelen: 17 + - condition: le + prelen: 18 + state: present + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_prefix_list + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_prefix_list/defaults/main.yml b/roles/os9_prefix_list/defaults/main.yml new file mode 100644 index 0000000..3226617 --- /dev/null +++ b/roles/os9_prefix_list/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_prefix_list \ No newline at end of file diff --git a/roles/os9_prefix_list/handlers/main.yml b/roles/os9_prefix_list/handlers/main.yml new file mode 100644 index 0000000..e1a2d95 --- /dev/null +++ b/roles/os9_prefix_list/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_prefix_list \ No newline at end of file diff --git a/roles/os9_prefix_list/meta/main.yml b/roles/os9_prefix_list/meta/main.yml new file mode 100644 index 0000000..1a2afe6 --- /dev/null +++ b/roles/os9_prefix_list/meta/main.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2017-2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_prefix_list role facilitates the configuration of prefix list attributes in devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_prefix_list/tasks/main.yml b/roles/os9_prefix_list/tasks/main.yml new file mode 100644 index 0000000..802068c --- /dev/null +++ b/roles/os9_prefix_list/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating prefix list configuration for os9" + template: + src: os9_prefixlist.j2 + dest: "{{ build_dir }}/prefixlist9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning prefix list configuration for os9" + os9_config: + src: os9_prefixlist.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_prefix_list/templates/os9_prefix_list.j2 b/roles/os9_prefix_list/templates/os9_prefix_list.j2 new file mode 100644 index 0000000..7f8da76 --- /dev/null +++ b/roles/os9_prefix_list/templates/os9_prefix_list.j2 @@ -0,0 +1,79 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{#################################### +Purpose: +Configure pl on OS9 devices +os9_prefix_list: + - name: testpl + type: ipv4 + description: pl + entries: + - number: 19 + permit: true + net_num: 20.0.0.0 + mask: 16 + condition_list: + - condition: ge + prelen: 17 + - condition: le + prelen: 18 + state: present + state: present +#####################################} +{% if (os9_prefix_list is defined and os9_prefix_list) %} + {% for val in os9_prefix_list %} + {% if val.name is defined and val.name %} + {% if val.state is defined and val.state == "absent" %} + {% if val.type is defined and val.type == "ipv4" %} +no ip prefix-list {{ val.name }} + {% elif val.type is defined and val.type == "ipv6" %} +no ipv6 prefix-list {{ val.name }} + {% endif %} + {% else %} + {% if val.type is defined and val.type == "ipv4" %} +ip prefix-list {{ val.name }} + {% elif val.type is defined and val.type == "ipv6" %} +ipv6 prefix-list {{ val.name }} + {% endif %} + {% if val.description is defined %} + {% if val.description %} + description {{ val.description }} + {% else %} + no description + {% endif %} + {% endif %} + {% if val.entries is defined and val.entries %} + {% for rule in val.entries %} + {% if rule.number is defined and rule.number %} + {% if rule.state is defined and rule.state == "absent" %} + no seq {{ rule.number }} + {% else %} + {% if rule.permit is defined %} + {% if rule.permit %} + {% set is_permit = "permit" %} + {% else %} + {% set is_permit = "deny" %} + {% endif %} + {% endif %} + {% if rule.net_num is defined and rule.net_num %} + {% if rule.net_num == "any" %} + seq {{rule.number}} {{is_permit}} any + {% elif rule.mask is defined and rule.mask %} + {% if rule.condition_list is defined and rule.condition_list %} + {% set condition_string = [' '] %} + {% set item = "" %} + {% for condition in rule.condition_list %} + {% set item= condition_string[0] + condition.condition + ' ' + condition.prelen|string + ' ' %} + {% if condition_string.insert(0,item) %} {% endif %} + {% endfor %} + seq {{rule.number}} {{is_permit}} {{rule.net_num}}/{{rule.mask}}{{ condition_string[0] }} + {% else %} + seq {{rule.number}} {{is_permit}} {{rule.net_num}}/{{rule.mask}} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} \ No newline at end of file diff --git a/roles/os9_prefix_list/tests/inventory.yaml b/roles/os9_prefix_list/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_prefix_list/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_prefix_list/tests/main.os9.yaml b/roles/os9_prefix_list/tests/main.os9.yaml new file mode 100644 index 0000000..aceb1cd --- /dev/null +++ b/roles/os9_prefix_list/tests/main.os9.yaml @@ -0,0 +1,33 @@ +--- +# vars file for dellemc.os9.os9_prefix_list, +# below gives a sample configuration +# Sample variables for OS9 device +os9_prefix_list: + - type: ipv4 + name: spine-leaf + description: Redistribute loopback and leaf networks + entries: + - number: 5 + permit: true + net_num: 10.0.0.0 + mask: 23 + condition_list: + - condition: ge + prelen: 32 + - number: 10 + permit: true + net_num: 10.0.0.0 + mask: 8 + condition_list: + - condition: ge + prelen: 26 + - number: 19 + permit: true + net_num: 20.0.0.0 + mask: 16 + condition_list: + - condition: ge + prelen: 17 + - condition: le + prelen: 18 + state: present \ No newline at end of file diff --git a/roles/os9_prefix_list/tests/test.yaml b/roles/os9_prefix_list/tests/test.yaml new file mode 100644 index 0000000..09ef1a3 --- /dev/null +++ b/roles/os9_prefix_list/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_prefix_list \ No newline at end of file diff --git a/roles/os9_prefix_list/vars/main.yml b/roles/os9_prefix_list/vars/main.yml new file mode 100644 index 0000000..9b3bccf --- /dev/null +++ b/roles/os9_prefix_list/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_prefix_list \ No newline at end of file diff --git a/roles/os9_sflow/LICENSE b/roles/os9_sflow/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_sflow/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_sflow/README.md b/roles/os9_sflow/README.md new file mode 100644 index 0000000..77736c5 --- /dev/null +++ b/roles/os9_sflow/README.md @@ -0,0 +1,125 @@ +sFlow role +========== + +This role facilitates the configuration of global and interface level sFlow attributes. It supports the configuration of sFlow collectors at the global level, enable/disable, and specification of sFlow polling-interval, sample-rate, max-datagram size, and so on are supported at the interface and global level. This role is abstracted for Dell EMC platforms running OS9. + +The os9_sflow role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take the dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- *os9_sflow* (dictionary) contains keys along with *interface name* (dictionary) +- Interface name can correspond to any of the valid os9 physical interfaces with the unique interface identifier name +- Interface name must be in * * format; physical interface name can be in *fortyGigE 1/1* format for os9 devices +- Variables and values are case-sensitive + +**os9_sflow keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``sflow_enable`` | boolean: true,false\* | Enables sFlow at a global level | os9 | +| ``collector`` | list | Configures collector information (see ``collector.*``); only two collectors can be configured on os9 devices | os9 | +| ``collector.collector_ip`` | string (required) | Configures an IPv4/IPv6 address for the collector | os9 | +| ``collector.agent_addr`` | string (required) | Configures an IPv4/IPv6 address for the sFlow agent to the collector | os9 | +| ``collector.udp_port`` | integer | Configures UDP port range at the collector level (1 to 65535) | os9 | +| ``collector.max_datagram_size`` | integer | Configures the maximum datagram size for the sFlow datagrams generated (400 to 1500) | os9 | +| ``collector.vrf`` | boolean: true,false* | Configures the management VRF to reach collector if set to true; can be enabled only for IPv4 collector addresses | os9 | +| ``polling_interval`` | integer | Configures the global default counter polling-interval (15 to 86400) | os9 | +| ``sample_rate`` | integer | Configures the global default sample-rate (256 to 8388608) | os9 | +| ``extended_switch`` | boolean: true,false\* | Enables packing extended information for the switch if set to true | os9 | +| ``max_header_size`` | boolean: true,false\* | Enables extended header copy size of 256 bytes if set to true at the global level | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +**interface name keys** + +| Key | Type | Notes | +|------------|---------------------------|---------------------------------------------------------| +| ``sflow_enable`` | boolean: true,false\* | Enables sFlow at the interface level | +| ``ingress_enable`` | boolean: true,false\* | Enables ingress sFlow at the interface level | +| ``polling_interval`` | integer | Configures the interface level default counter polling-interval (15 to 86400) | +| ``max_header_size`` | boolean: true,false\* | Enables extended header copy size of 256 bytes if set to true at the interface level | +| ``sample_rate`` | integer | Configures the interface level default sample-rate (256 to 8388608) | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories,or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_sflow* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_sflow* role to configure sFlow attributes at interface and global level. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with the corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_sflow* role. By including the role, you automatically get access to all of the tasks to configure sFlow features. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_sflow: + sflow_enable: true + collector: + - collector_ip: 1.1.1.1 + agent_addr: 2.2.2.2 + udp_port: 2 + max_datagram_size: 1000 + vrf: true + state: present + polling_interval: 30 + sample_rate: 1024 + extended_switch : true + max_header_size: true + fortyGigE 1/1: + sflow_enable : true + ingress_enable: true + polling_interval: 30 + sample_rate: 1024 + max_header_size: true + +**Simple playbook to setup sflow - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_sflow + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_sflow/defaults/main.yml b/roles/os9_sflow/defaults/main.yml new file mode 100644 index 0000000..ecfc706 --- /dev/null +++ b/roles/os9_sflow/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_sflow \ No newline at end of file diff --git a/roles/os9_sflow/handlers/main.yml b/roles/os9_sflow/handlers/main.yml new file mode 100644 index 0000000..1441cc3 --- /dev/null +++ b/roles/os9_sflow/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_sflow \ No newline at end of file diff --git a/roles/os9_sflow/meta/main.yml b/roles/os9_sflow/meta/main.yml new file mode 100644 index 0000000..4e3eba5 --- /dev/null +++ b/roles/os9_sflow/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_sflow role facilitates the configuration of sflow attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_sflow/tasks/main.yml b/roles/os9_sflow/tasks/main.yml new file mode 100644 index 0000000..4c929c5 --- /dev/null +++ b/roles/os9_sflow/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating sflow configuration for os9" + template: + src: os9_sflow.j2 + dest: "{{ build_dir }}/sflow9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning sflow configuration for os9" + os9_config: + src: os9_sflow.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_sflow/templates/os9_sflow.j2 b/roles/os9_sflow/templates/os9_sflow.j2 new file mode 100644 index 0000000..be9c47d --- /dev/null +++ b/roles/os9_sflow/templates/os9_sflow.j2 @@ -0,0 +1,143 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure sflow commands for os9 Devices +os9_sflow: + sflow_enable: true + collector: + - collector_ip: 1.1.1.1 + agent_addr: 2.2.2.2 + udp_port: 2 + max_datagram_size: 1000 + vrf: true + state: present + polling_interval: 30 + sample_rate: 1024 + extended_switch : true + max_header_size: true + fortyGigE 1/1: + sflow_enable : true + ingress_enable: true + polling_interval: 30 + sample_rate: 1024 + max_header_size: true +###################################################} +{% if os9_sflow is defined and os9_sflow %} + +{% if os9_sflow %} +{% for key,value in os9_sflow.items() %} + {% if key == "sflow_enable" %} + {% if value %} +sflow enable + {% else %} +no sflow enable + {% endif %} + + {% elif key == "collector" %} + {% if value %} + {% for item in value %} + {% if item.state is defined and item.state == "absent" %} + {% if item.collector_ip is defined and item.agent_addr is defined %} + {% if item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.max_datagram_size is defined and item.max_datagram_size and item.vrf is defined and item.vrf %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} max-datagram-size {{ item.max_datagram_size }} vrf management + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.max_datagram_size is defined and item.max_datagram_size %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} max-datagram-size {{ item.max_datagram_size }} + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.vrf is defined and item.vrf %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} vrf management + {% elif item.collector_ip and item.agent_addr and item.vrf is defined and item.vrf and item.max_datagram_size is defined and item.max_datagram_size %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} max-datagram-size {{ item.max_datagram_size }} vrf management + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} + {% elif item.collector_ip and item.agent_addr and item.max_datagram_size is defined and item.max_datagram_size %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} max-datagram-size {{ item.max_datagram_size }} + {% elif item.collector_ip and item.agent_addr and item.vrf is defined and item.vrf %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} vrf management + {% elif item.collector_ip and item.agent_addr %} +no sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} + {% endif %} + {% endif %} + {% else %} + {% if item.collector_ip is defined and item.agent_addr is defined %} + {% if item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.max_datagram_size is defined and item.max_datagram_size and item.vrf is defined and item.vrf %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} max-datagram-size {{ item.max_datagram_size }} vrf management + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.max_datagram_size is defined and item.max_datagram_size %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} max-datagram-size {{ item.max_datagram_size }} + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port and item.vrf is defined and item.vrf %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} vrf management + {% elif item.collector_ip and item.agent_addr and item.vrf is defined and item.vrf and item.max_datagram_size is defined and item.max_datagram_size %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} max-datagram-size {{ item.max_datagram_size }} vrf management + {% elif item.collector_ip and item.agent_addr and item.udp_port is defined and item.udp_port %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} {{ item.udp_port }} + {% elif item.collector_ip and item.agent_addr and item.max_datagram_size is defined and item.max_datagram_size %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} max-datagram-size {{ item.max_datagram_size }} + {% elif item.collector_ip and item.agent_addr and item.vrf is defined and item.vrf %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} vrf management + {% elif item.collector_ip and item.agent_addr %} +sflow collector {{ item.collector_ip }} agent-addr {{ item.agent_addr }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key =="polling_interval" %} + {% if value %} +sflow polling-interval {{ value }} + {% else %} +no sflow polling-interval + {% endif %} + + {% elif key =="sample_rate" %} + {% if value %} +sflow sample-rate {{ value }} + {% else %} +no sflow sample-rate + {% endif %} + + {% elif key == "extended_switch" %} + {% if value %} +sflow extended-switch enable + {% else %} +no sflow extended-switch enable + {% endif %} + + {% elif key == "max_header_size" %} + {% if value %} +sflow max-header-size extended + {% else %} +no sflow max-header-size extended + {% endif %} + + {% elif '/' in key %} + {% set intf_vars = os9_sflow[key] %} +interface {{ key }} + {% if intf_vars.sflow_enable is defined and intf_vars.sflow_enable %} + sflow enable + {% else %} + no sflow enable + {% endif %} + {% if intf_vars.ingress_enable is defined and intf_vars.ingress_enable %} + sflow ingress-enable + {% else %} + no sflow ingress-enable + {% endif %} + {% if intf_vars.max_header_size is defined and intf_vars.max_header_size %} + sflow max-header-size extended + {% else %} + no sflow max-header-size extended + {% endif %} + {% if intf_vars.polling_interval is defined and intf_vars.polling_interval %} + sflow polling-interval {{ intf_vars.polling_interval }} + {% else %} + no sflow polling-interval + {% endif %} + {% if intf_vars.sample_rate is defined and intf_vars.sample_rate %} + sflow sample-rate {{ intf_vars.sample_rate }} + {% else %} + no sflow sample-rate + {% endif %} + + {% endif %} +{% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_sflow/tests/inventory.yaml b/roles/os9_sflow/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_sflow/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_sflow/tests/main.os9.yaml b/roles/os9_sflow/tests/main.os9.yaml new file mode 100644 index 0000000..548611c --- /dev/null +++ b/roles/os9_sflow/tests/main.os9.yaml @@ -0,0 +1,35 @@ +--- +# vars file for dellemc.os9.os9_sflow, +# below gives a sample configuration +# Sample variables for OS9 device +os9_sflow: + sflow: true + collector: + - collector_ip: 1.1.1.1 + agent_addr: 2.2.2.2 + udp_port: + max_datagram_size: 1000 + vrf: true + state: present + - collector_ip: 2.2.2.2 + agent_addr: 2.2.2.2 + udp_port: 3 + max_datagram_size: 1002 + vrf: test + state: absent + polling_interval: 24 + sample_rate: 256 + extended_switch: true + max_header_size: true + fortyGigE 1/1: + sflow: true + ingress_enable: true + polling_interval: 30 + sample_rate: 1024 + max_header_size: true + fortyGigE 1/2: + sflow: true + ingress_enable: true + polling_interval: 20 + sample_rate: 256 + max_header_size: true \ No newline at end of file diff --git a/roles/os9_sflow/tests/test.yaml b/roles/os9_sflow/tests/test.yaml new file mode 100644 index 0000000..8f931d3 --- /dev/null +++ b/roles/os9_sflow/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_sflow \ No newline at end of file diff --git a/roles/os9_sflow/vars/main.yml b/roles/os9_sflow/vars/main.yml new file mode 100644 index 0000000..e79c81b --- /dev/null +++ b/roles/os9_sflow/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_sflow \ No newline at end of file diff --git a/roles/os9_snmp/LICENSE b/roles/os9_snmp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_snmp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_snmp/README.md b/roles/os9_snmp/README.md new file mode 100644 index 0000000..e76c5a8 --- /dev/null +++ b/roles/os9_snmp/README.md @@ -0,0 +1,197 @@ +SNMP role +========= + +This role facilitates the configuration of global SNMP attributes. It supports the configuration of SNMP server attributes including users, group, community, location, and traps. This role is abstracted for Dell EMC platforms running OS9 + +The SNMP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_snmp keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``snmp_contact`` | string | Configures SNMP contact information | os9 | +| ``snmp_server_vrf`` | boolean: true, false\* | Enables SNMP-server VRF globally | os9 | +| ``snmp_location`` | string | Configures SNMP location information | os9 | +| ``snmp_community`` | list | Configures SNMP community information (see ``snmp_community.*``) | os9 | +| ``snmp_community.name`` | string (required) | Configures the SNMP community string | os9 | +| ``snmp_community.access_mode`` | string: ro,rw | Configures access-mode for the community | os9 | +| ``snmp_community.state`` | string: absent,present\* | Deletes the SNMP community information if set to absent | os9 | +| ``snmp_host`` | list | Configures SNMP hosts to receive SNMP traps (see ``snmp_host.*``) | os9 | +| ``snmp_host.ipv4`` | string | Configures the IPv4 address for the SNMP trap host | os9 | +| ``snmp_host.ipv6`` | stirng | Configures the IPv6 address for the SNMP trap host | os9 | +| ``snmp_host.communitystring`` | string | Configures the SNMP community string of the trap host | os9 | +| ``snmp_host.udpport`` | string | Configures the UDP number of the SNMP trap host (0 to 65535) | os9 | +| ``snmp_host.version`` | string (required) | Specifies the SNMP version of the host (either 1 or 2c or 3 in os9) | os9 | +| ``snmp_host.vrf`` | list | Configures the SNMP VRF trap for the SNMP host (list of VRF names) | os9 | +| ``snmp_host.state`` | string: absent,present\* | Deletes the SNMP trap host if set to absent | os9 | +| ``snmp_traps`` | list | Configures SNMP traps (see ``snmp_traps.*``) | os9 | +| ``snmp_traps.name`` | string | Enables SNMP traps | os9 | +| ``snmp_traps.state`` | string: absent,present\* | Deletes the SNMP trap if set to absent | os9 | +| ``snmp_engine_id`` | string | Configures the SNMPv3 engineID for the local agent | os9 | +| ``snmp_view`` | list | Configures SNMPv3 view information (see ``snmp_view.*``) | os9 | +| ``snmp_view.name`` | string | Configures the SNMP view name (20 characters maximum) | os9 | +| ``snmp_view.oid_subtree`` | integer | Configures the SNMP view for the OID subtree | os9 | +| ``snmp_view.include`` | boolean: true,false | Specifies whether the MIB family should be included or excluded from the view | os9 | +| ``snmp_user`` | list | Configures SNMP users for each group name (see ``snmp_user.*``) | os9 | +| ``snmp_user.name`` | string (required) | Configures the SNMP user name | os9 | +| ``snmp_user.group_name`` | string (required) | Configures the SNMP group name for the user | os9 | +| ``snmp_user.version`` | string: 1,2c,3 (required) | Configures a user entry with the specified SNMP version (either 1 or 2c or 3) | os9 | +| ``snmp_user.access_list`` | dictionary | Configures access-list details; required to configure or negate if defined | os9 | +| ``snmp_user.access_list.access`` | string | Configures the access-list associated with the user | os9 | +| ``snmp_user.access_list.ipv6`` | string | Configures the IPv6 access-list associated with the user | os9 | +| ``snmp_user.encryption`` | boolean: true,false\* | Specifies the encryption for the SNMP user if set to true | os9 | +| ``snmp_user.auth_algorithm`` | string: md5,sha | Configures the authorization algorithm for the SNMP user | os9 | +| ``snmp_user.auth_pass`` | string | Configures the authentication password for the user | os9 | +| ``snmp_user.state`` | string: absent,present\* | Deletes the SNMP user if set to absent | os9 | +| ``snmp_group`` | list | Configures SNMP groups (see ``snmp_group.*``) | os9 | +| ``snmp_group.name`` | string (required) | Configures the SNMP group name | os9 | +| ``snmp_group.version`` | string (required) | Configures the group entry with the specified SNMP version (either 1 or 2c or 3) | os9 | +| ``snmp_group.access_list`` | dict | Configures access-list entries for the group; required to configure or negate if defined | os9 | +| ``snmp_group.access_list.access`` | string | Configures the access-list associated with the group | os9 | +| ``snmp_group.access_list.ipv6`` | string | Configures the IPv6 access-list associated with the group | os9 | +| ``snmp_group.view`` | dict | Configures view entries for the group; required to configure or negate if defined | os9 | +| ``snmp_group.view.notify`` | string | Configures notify view associated with the group | os9 | +| ``snmp_group.view.read`` | string | Configures read view associated with the group | os9 | +| ``snmp_group.view.write`` | string | Configures write view associated with the group | os9 | +| ``snmp_group.context`` | list | Configures context list entries (see ``snmp_group.context.*``) | os9 | +| ``snmp_group.context.context_name`` | string | Configures SNMP-group entries with specified context name | os9 | +| ``snmp_group.context.access_list`` | dictionary | Configures access-list entries for the group with context | os9 | +| ``snmp_group.context.access_list.access`` | string | Configures the access-list associated with the group | os9 | +| ``snmp_group.context.access_list.ipv6`` | string | Configures the IPv6 access-list associated with the group | os9 | +| ``snmp_group.context.view`` | dictionary | Configures view entries for the group with context | os9 | +| ``snmp_group.context.view.notify`` | string | Configures notify view associated with the group | os9 | +| ``snmp_group.context.view.read`` | string | Configures read view associated with the group | os9 | +| ``snmp_group.context.view.write`` | string | Configures write view associated with the group | os9 | +| ``snmp_group.context.state`` | string: absent,present | Deletes the context entries with the group if set to absent | os9 | +| ``snmp_group.state`` | string: absent,present\* | Deletes the associated SNMP group if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_snmp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_snmp* role to completely set up the SNMP server attributes. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_snmp* role. By including the role, you automatically get access to all of the tasks to configure SNMP features. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_snmp: + snmp_contact: test + snmp_location: chennai + snmp_server_vrf: test + snmp_community: + - name: public + access_mode: ro + state: present + - name: private + access_mode: rw + state: present + snmp_host: + - ipv6: 2001:4898:f0:f09b::2000 + version: "3" + security_level: auth + communitystring: + udpport: + state: absent + snmp_traps: + - name: config + state: present + snmp_engine_id: 1234567890 + snmp_view: + - name: view_1 + oid_subtree: 2 + include: false + state: absent + snmp_user: + - name: user_1 + group_name: grp1 + version: 3 + access_list: + access: a1 + ipv6: ip1 + encryption: true + auth_algorithm: md5 + auth_pass: 12345678 + state: present + snmp_group: + - name: group_1 + version: 2c + access_list: + access: a1 + ipv6: ip1 + state: absent + - name: group_2 + version: 3 + security_level: priv + access_list: + access: a1 + ipv6: ip1 + context: + - context_name: c1 + state: present + - context_name: c2 + access_list: + access: a1 + view: + read: r1 + state: present + state: present + +**Simple playbook to setup snmp - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_snmp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_snmp/defaults/main.yml b/roles/os9_snmp/defaults/main.yml new file mode 100644 index 0000000..22c7b89 --- /dev/null +++ b/roles/os9_snmp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_snmp \ No newline at end of file diff --git a/roles/os9_snmp/handlers/main.yml b/roles/os9_snmp/handlers/main.yml new file mode 100644 index 0000000..f04bb2b --- /dev/null +++ b/roles/os9_snmp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_snmp \ No newline at end of file diff --git a/roles/os9_snmp/meta/main.yml b/roles/os9_snmp/meta/main.yml new file mode 100644 index 0000000..9aa992b --- /dev/null +++ b/roles/os9_snmp/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_snmp role facilitates the configuration of snmp attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_snmp/tasks/main.yml b/roles/os9_snmp/tasks/main.yml new file mode 100644 index 0000000..92c2f5b --- /dev/null +++ b/roles/os9_snmp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating SNMP configuration for os9" + template: + src: os9_snmp.j2 + dest: "{{ build_dir }}/snmp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning SNMP configuration for os9" + os9_config: + src: os9_snmp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_snmp/templates/os9_snmp.j2 b/roles/os9_snmp/templates/os9_snmp.j2 new file mode 100644 index 0000000..6033604 --- /dev/null +++ b/roles/os9_snmp/templates/os9_snmp.j2 @@ -0,0 +1,524 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure snmp commands for os9 Devices +os9_snmp: + snmp_contact: test + snmp_location: chennai + snmp_server_vrf: test + snmp_community: + - name: public + access_mode: ro + state: present + - name: private + access_mode: rw + state: present + snmp_context: + - name: SNMP1 + state: absent + snmp_packet_size: 8 + snmp_host: + - ipv4: 1.1.1.1 + version: 3 + security_level: auth + vrf: + - test + - management + communitystring: msft + udpport: 162 + state: absent + - ipv6: 2001:4898:f0:f09b::2000 + version: 1 + state: present + snmp_traps: + - name: config + state: present + snmp_engine_id: 1234567890 + snmp_view: + - name: view_1 + oid_subtree: 2 + include: true + state: absent + snmp_user: + - name: user_1 + group_name: grp1 + encryption : true + auth_algorithm: md5 + auth_pass: 12345678 + version: 3 + access_list: + access: a2 + ipv6: ip1 + state: present + - name: user_2 + group_name: grp2 + version: "2c" + access_list: + ipv6: ip1 + state: absent + snmp_group: + - name: group_1 + version: 2c + access_list: + access: a1 + ipv6: ip1 + view: + read: r1 + write: w1 + notify: n1 + context: + - context_name: c1 + access_list: + access: a1 + ipv6: ip1 + view: + read: r1 + write: w1 + notify: n1 + state: present + - context_name: c2 + state: present + state: present + - name: group_2 + version: 3 + security_level: auth + access_list: + access: a1 + ipv6: ip1 + state: present +###################################################} +{% if os9_snmp is defined and os9_snmp %} + +{% if os9_snmp %} +{% for key,value in os9_snmp.items() %} + {% if key == "snmp_contact" %} + {% if value %} +snmp-server contact {{ value }} + {% else %} +no snmp-server contact + {% endif %} + + {% elif key == "snmp_location" %} + {% if value %} +snmp-server location {{ value }} + {% else %} +no snmp-server location + {% endif %} + + {% elif key == "snmp_server_vrf" %} + {% if value %} +snmp-server vrf {{ value }} + {% else %} +no snmp-server vrf + {% endif %} + + {% elif key == "snmp_community" %} + {% if value %} + {% for item in value %} + {% if item.name is defined and item.name %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server community {{ item.name }} + {% else %} + {% if item.access_mode is defined and item.access_mode %} +snmp-server community {{ item.name }} {{ item.access_mode }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "snmp_packet_size" %} + {% if value %} +snmp-server packetsize {{ value }} + {% else %} +no snmp-server packetsize + {% endif %} + + {% elif key == "snmp_context" %} + {% if value %} + {% for item in value %} + {% if item.name is defined and item.name %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server context {{ item.name }} + {% else %} +snmp-server context {{ item.name }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "snmp_host" and value %} + {% for item in value %} + {% if item.version is defined and item.version == "2c" or item.version == 1 %} + {% set my_version = item.version|string %} + {% elif item.version is defined and item.version == 3 %} + {% if item.security_level is defined and item.security_level %} + {% set my_version = "3"+" "+item.security_level %} + {% endif %} + {% endif %} + {% if item.state is defined and item.state == "absent" %} + {% if item.vrf is defined and item.vrf %} + {% for vrf_name in item.vrf %} + {% if item.ipv4 is defined and item.ipv4 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +no snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +no snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} {{ item.communitystring }} + {% endif %} + {% else %} +no snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% endif %} + {% endfor %} + {% else %} + {% if item.ipv4 is defined and item.ipv4 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +no snmp-server host {{ item.ipv4 }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +no snmp-server host {{ item.ipv4 }} traps version {{ my_version }} {{ item.communitystring }} + {% endif %} + {% else %} +no snmp-server host {{ item.ipv4 }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% elif item.ipv6 is defined and item.ipv6 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +no snmp-server host {{ item.ipv6 }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +no snmp-server host {{ item.ipv6 }} traps version {{ my_version }} {{ item.communitystring }} + {% endif %} + {% else %} +no snmp-server host {{ item.ipv6 }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% endif %} + {% endif %} + {% else %} + {% if item.vrf is defined and item.vrf %} + {% for vrf_name in item.vrf %} + {% if item.ipv4 is defined and item.ipv4 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} {{ item.communitystring }} udp-port 162 + {% endif %} + {% else %} +snmp-server host {{ item.ipv4 }} vrf {{ vrf_name }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% endif %} + {% endfor %} + {% else %} + {% if item.ipv4 is defined and item.ipv4 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +snmp-server host {{ item.ipv4 }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +snmp-server host {{ item.ipv4 }} traps version {{ my_version }} {{ item.communitystring }} udp-port 162 + {% endif %} + {% else %} +snmp-server host {{ item.ipv4 }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% elif item.ipv6 is defined and item.ipv6 %} + {% if item.communitystring is defined and item.communitystring %} + {% if item.udpport is defined and item.udpport %} +snmp-server host {{ item.ipv6 }} traps version {{ my_version }} {{ item.communitystring }} udp-port {{ item.udpport }} + {% else %} +snmp-server host {{ item.ipv6 }} traps version {{ my_version }} {{ item.communitystring }} udp-port 162 + {% endif %} + {% else %} +snmp-server host {{ item.ipv6 }} traps version {{ my_version }} public udp-port 162 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + + {% elif key == "snmp_traps" %} + {% if value %} + {% for val in value %} + {% if val.name is defined and val.name %} + {% if val.state is defined and val.state == "absent" %} + {% if val.name == "all" %} +no snmp-server enable traps + {% else %} +no snmp-server enable traps {{ val.name }} + {% endif %} + {% else %} + {% if val.name == "all" %} + {% set trap_list = ['bgp','snmp authentication coldstart linkdown linkup syslog-reachable syslog-unreachable','vrrp','lacp','entity','stack','stp','ecfm','vlt','fips','ets','xstp','isis','config','pfc','envmon cam-utilization fan supply temperature','ecmp'] %} + {% for name in trap_list %} +snmp-server enable traps {{ name }} + {% endfor %} + {% else %} +snmp-server enable traps {{ val.name }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "snmp_engine_id" %} + {% if value %} +snmp-server engineID local {{ value }} + {% else %} +no snmp-server engineID local + {% endif %} + + {% elif key == "snmp_view" %} + {% if value %} + {% for item in value %} + {% if item.name is defined and item.name %} + {% if item.oid_subtree is defined and item.oid_subtree %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server view {{ item.name }} {{ item.oid_subtree }} + {% else %} + {% if item.include is defined %} + {% if item.include %} +snmp-server view {{ item.name }} {{ item.oid_subtree }} included + {% elif not item.include %} +snmp-server view {{ item.name }} {{ item.oid_subtree }} excluded + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "snmp_user" %} + {% if value %} + {% for item in value %} + {% if item.name is defined and item.name %} + {% if item.group_name is defined and item.group_name %} + {% if item.version is defined and item.version == "2c" or item.version == 1 %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server user {{ item.name }} {{ item.group_name }} {{ item.version|string }} + {% else %} + {% if item.access_list is defined and item.access_list %} + {% if item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} {{ item.version|string }} access {{ item.access_list.access }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.access_list.access is defined and item.access_list.access %} +snmp-server user {{ item.name }} {{ item.group_name }} {{ item.version|string }} access {{ item.access_list.access }} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} {{ item.version|string }} ipv6 {{ item.access_list.ipv6 }} + {% endif %} + {% else %} +snmp-server user {{ item.name }} {{ item.group_name }} {{ item.version|string }} + {% endif %} + {% endif %} + {% elif item.version is defined and item.version == 3 %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server user {{ item.name }} {{ item.group_name }} 3 + {% else %} + {% if item.access_list is defined and item.access_list %} + {% if item.encryption is defined and item.encryption and item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 encrypted auth {{ item.auth_algorithm }} {{ item.auth_pass }} access {{ item.access_list.access }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.encryption is defined and item.encryption and item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.access is defined and item.access_list.access %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 encrypted auth {{ item.auth_algorithm }} {{ item.auth_pass }} access {{ item.access_list.access }} + {% elif item.encryption is defined and item.encryption and item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 encrypted auth {{ item.auth_algorithm }} {{ item.auth_pass }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.encryption is defined and item.encryption and item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 encrypted auth {{ item.auth_algorithm }} {{ item.auth_pass }} + {% elif item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 auth {{ item.auth_algorithm }} {{ item.auth_pass }} access {{ item.access_list.access }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.access is defined and item.access_list.access %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 auth {{ item.auth_algorithm }} {{ item.auth_pass }} access {{ item.access_list.access }} + {% elif item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 auth {{ item.auth_algorithm }} {{ item.auth_pass }} access {{ item.access_list.access }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.auth_algorithm is defined and item.auth_algorithm and item.auth_pass is defined and item.auth_pass %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 auth {{ item.auth_algorithm }} {{ item.auth_pass }} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 access {{ item.access_list.access }} ipv6 {{ item.access_list.ipv6 }} + {% elif item.access_list.access is defined and item.access_list.access %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 access {{ item.access_list.access }} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 %} +snmp-server user {{ item.name }} {{ item.group_name }} 3 ipv6 {{ item.access_list.ipv6 }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "snmp_group" and value %} + {% for item in value %} + {% if item.name is defined and item.name %} + {% if item.version is defined and item.version == "2c" or item.version == 1 %} + {% set my_version = item.version|string %} + {% elif item.version is defined and item.version == 3 %} + {% if item.security_level is defined and item.security_level %} + {% set my_version = "3"+" "+item.security_level %} + {% endif %} + {% endif %} + {% if item.context is defined and item.context %} + {% set my_entry = [] %} + {% for it in item.context %} + {% if it.context_name is defined and it.context_name %} + {% if it.access_list is defined and it.access_list and it.view is defined and it.view %} + {% if it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" notify "+it.view.notify+" read "+it.view.read+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" notify "+it.view.notify+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" notify "+it.view.notify+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.write is defined and it.view.write and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" write "+it.view.write+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" notify "+it.view.notify) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6 +" write "+it.view.write) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read and it.view.write is defined and it.view.write%} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" notify "+it.view.notify+" read "+it.view.read+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" notify "+it.view.notify+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.notify is defined and it.view.notify and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" notify "+it.view.notify+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.write is defined and it.view.write and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" write "+it.view.write+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.notify is defined and it.view.notify %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" notify "+it.view.notify) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read and it.view.write is defined and it.view.write%} + {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" notify "+it.view.notify+" read "+it.view.read+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" notify "+it.view.notify+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" notify "+it.view.notify+" write "+it.view.write) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.write is defined and it.view.write and it.view.read is defined and it.view.read %} {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" write "+it.view.write+" read "+it.view.read) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.notify is defined and it.view.notify %} {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" notify "+it.view.notify) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+"read "+it.view.read) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 and it.view.write is defined and it.view.write %} {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6+" write "+it.view.write) %}{% endif %} + {% endif %} + {% elif it.access_list is defined and it.access_list %} + {% if it.access_list.access is defined and it.access_list.access and it.access_list.ipv6 is defined and it.access_list.ipv6 %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access+" ipv6 "+it.access_list.ipv6) %}{% endif %} + {% elif it.access_list.access is defined and it.access_list.access %} + {% if my_entry.append("context "+it.context_name+" access "+it.access_list.access) %}{% endif %} + {% elif it.access_list.ipv6 is defined and it.access_list.ipv6 %} + {% if my_entry.append("context "+it.context_name+" ipv6 "+it.access_list.ipv6) %}{% endif %} + {% endif %} + {% elif it.view is defined and it.view %} + {% if it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" notify "+it.view.notify+" read "+it.view.read+" write "+it.view.write) %}{% endif %} + {% elif it.view.notify is defined and it.view.notify and it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" notify "+it.view.notify+" read "+it.view.read) %}{% endif %} + {% elif it.view.notify is defined and it.view.notify and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" notify "+it.view.notify+" write "+it.view.write) %}{% endif %} + {% elif it.view.read is defined and it.view.read and it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" read "+it.view.read+" write "+it.view.write) %}{% endif %} + {% elif it.view.read is defined and it.view.read %} + {% if my_entry.append("context "+it.context_name+" read "+it.view.read) %}{% endif %} + {% elif it.view.notify is defined and it.view.notify %} + {% if my_entry.append("context "+it.context_name+" notify "+it.view.notify) %}{% endif %} + {% elif it.view.write is defined and it.view.write %} + {% if my_entry.append("context "+it.context_name+" write "+it.view.write) %}{% endif %} + {% endif %} + {% else %} + {% if my_entry.append("context "+it.context_name) %}{% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if item.access_list is defined and item.access_list and item.view is defined and item.view %} + {% if item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify+" read "+item.view.read+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify+" read "+item.view.read %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" read "+item.view.read+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.read is defined and item.view.read %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 +" read "+item.view.read %} + {% elif item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" notify "+item.view.notify+" read "+item.view.read+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read %} + {% set my_en = "access "+item.access_list.access+" notify "+item.view.notify+" read "+item.view.read %} {% elif item.access_list.access is defined and item.access_list.access and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" read "+item.view.read+" write "+item.view.write %} {% elif item.access_list.access is defined and item.access_list.access and item.view.notify is defined and item.view.notify and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access +" notify "+item.view.notify+" write "+item.view.write %} + {% elif item.access_list.access is defined and item.access_list.access and item.view.notify is defined and item.view.notify %} + {% set my_en = "access "+item.access_list.access +" notify "+item.view.notify %} + {% elif item.access_list.access is defined and item.access_list.access and item.view.read is defined and item.view.read %} + {% set my_en = "access "+item.access_list.access+" read "+item.view.read %} + {% elif item.access_list.access is defined and item.access_list.access and item.view.write is defined and item.view.write %} + {% set my_en = "access "+item.access_list.access+" write "+item.view.write %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "ipv6 "+item.access_list.ipv6+" notify "+item.view.notify+" read "+item.view.read+" write "+item.view.write %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read %} + {% set my_en = "ipv6 "+item.access_list.ipv6+" notify "+item.view.notify+" read "+item.view.read %} {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "ipv6 "+item.access_list.ipv6+" read "+item.view.read+" write "+item.view.write %} {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify and item.view.write is defined and item.view.write %} + {% set my_en = "ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify+" write "+item.view.write %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.notify is defined and item.view.notify %} + {% set my_en = "ipv6 "+item.access_list.ipv6 +" notify "+item.view.notify %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.read is defined and item.view.read %} + {% set my_en = "ipv6 "+item.access_list.ipv6+" read "+item.view.read %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 and item.view.write is defined and item.view.write %} + {% set my_en = "ipv6 "+item.access_list.ipv6+" write "+item.view.write %} + + {% endif %} + {% elif item.access_list is defined and item.access_list %} + {% if item.access_list.access is defined and item.access_list.access and item.access_list.ipv6 is defined and item.access_list.ipv6 %} + {% set my_en = "access "+item.access_list.access+" ipv6 "+item.access_list.ipv6 %} + {% elif item.access_list.access is defined and item.access_list.access %} + {% set my_en = "access "+item.access_list.access %} + {% elif item.access_list.ipv6 is defined and item.access_list.ipv6 %} + {% set my_en = "ipv6 "+item.access_list.ipv6 %} + {% endif %} + {% elif item.view is defined and item.view %} + {% if item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "notify "+item.view.notify+" read "+item.view.read+" write "+item.view.write %} + {% elif item.view.notify is defined and item.view.notify and item.view.read is defined and item.view.read %} + {% set my_en = "notify "+item.view.notify+" read "+item.view.read %} + {% elif item.view.notify is defined and item.view.notify and item.view.write is defined and item.view.write %} + {% set my_en ="notify "+item.view.notify+" write "+item.view.write %} + {% elif item.view.read is defined and item.view.read and item.view.write is defined and item.view.write %} + {% set my_en = "read "+item.view.read+" write "+item.view.write %} + {% elif item.view.read is defined and item.view.read %} + {% set my_en = "read "+item.view.read %} + {% elif item.view.notify is defined and item.view.notify %} + {% set my_en = "notify "+item.view.notify %} + {% elif item.view.write is defined and item.view.write %} + {% set my_en = "write "+item.view.write %} + {% endif %} + {% endif %} + {% if item.state is defined and item.state == "absent" %} +no snmp-server group {{ item.name }} {{ my_version }} + {% else %} + {% if my_en is defined and my_en %} +snmp-server group {{ item.name }} {{ my_version }} {{ my_en }} + {% else %} +snmp-server group {{ item.name }} {{ my_version }} + {% endif %} + {% endif %} + {% set my_en = "" %} + {% if item.context is defined %} + {% set i = 0 %} + {% for it in item.context %} + {% if it.state is defined and it.state == "absent" %} +no snmp-server group {{ item.name }} {{ my_version }} context {{ it.context_name }} + {% else %} +snmp-server group {{ item.name }} {{ my_version }} {{ my_entry[i] }} + {% endif %} + {% set i = i+1 %} + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +{% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_snmp/tests/inventory.yaml b/roles/os9_snmp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_snmp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_snmp/tests/main.os9.yaml b/roles/os9_snmp/tests/main.os9.yaml new file mode 100644 index 0000000..98cba1e --- /dev/null +++ b/roles/os9_snmp/tests/main.os9.yaml @@ -0,0 +1,83 @@ +--- +# vars file for dellemc.os9.os9_snmp, +# below gives a sample configuration +# Sample variables for OS9 device +os9_snmp: + snmp_contact: test + snmp_location: chennai + snmp_server_vrf: test + snmp_context: + - name: SNMP1 + state: present + snmp_packet_size: 16 + snmp_community: + - name: public + access_mode: ro + state: present + - name: private + access_mode: rw + state: present + snmp_host: + - ipv4: 1.1.1.1 + version: 3 + vrf: + - test + - management + security_level: noauth + communitystring: ab + udpport: 1 + state: absent + - ipv6: 2001:4898:f0:f09b::2000 + version: 1 + state: present + snmp_traps: + - name: config + state: present + snmp_engine_id: 1234567890 + snmp_view: + - name: view_1 + oid_subtree: 2 + include: false + state: absent + snmp_user: + - name: user_1 + group_name: grp1 + version: 3 + access_list: + access: a1 + encryption: true + auth_algorithm: md5 + auth_pass: 12345678 + state: present + - name: user_2 + group_name: grp1 + version: "2c" + access_list: + access: a2 + ipv6: ip1 + state: present + snmp_group: + - name: group_1 + version: 2c + access_list: + access: a1 + ipv6: ip1 + context: + - context_name: c1 + state: present + - context_name: c2 + access_list: + access: a1 + ipv6: ip1 + view: + notify: n1 + read: r1 + write: w1 + state: absent + - name: group_2 + version: 3 + security_level: priv + access_list: + access: a1 + ipv6: ip1 + state: present \ No newline at end of file diff --git a/roles/os9_snmp/tests/test.yaml b/roles/os9_snmp/tests/test.yaml new file mode 100644 index 0000000..cc1736a --- /dev/null +++ b/roles/os9_snmp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_snmp \ No newline at end of file diff --git a/roles/os9_snmp/vars/main.yml b/roles/os9_snmp/vars/main.yml new file mode 100644 index 0000000..9fa3643 --- /dev/null +++ b/roles/os9_snmp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_snmp \ No newline at end of file diff --git a/roles/os9_system/LICENSE b/roles/os9_system/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_system/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_system/README.md b/roles/os9_system/README.md new file mode 100644 index 0000000..83eed0d --- /dev/null +++ b/roles/os9_system/README.md @@ -0,0 +1,228 @@ +System role +=========== + +This role facilitates the configuration of global system attributes, and is abstracted for Dell EMC platforms running OS9. It specifically enables configuration of hostname and enable password. It supports the configuration of management route, hash alogrithm, clock, line terminal, banner, and reload type. + +The os9_system role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc_netowrking.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_system keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``hostname`` | string | Configures a hostname to the device (no negate command) | os9 | +| ``unique_hostname`` | boolean: true,false\* | Configures a unique hostname in the switch | os9 | +| ``enable_password`` | string | Configures the enable password | os9 | +| ``management_rt`` | list | Configures the management route | os9 | +| ``management_rt.ip`` | string (required) | Configures the IP destination prefix for the management route (A.B.C.D format for IPv4, A:B:C:D::E format for IPv6) | os9 | +| ``management_rt.ipv4`` | boolean: true\*,false | Specifies if the management route is an IPv4 or IPv6 address; if false or undefined, the IP is set as IPv6 | os9 | +| ``management_rt.state`` | string: absent,present\* | Deletes the management route if set to absent | os9 | +| ``line_terminal`` | dictionary | Configures the terminal line (see ``line_terminal.*``) | os9 | +| ``line_terminal.`` | dictionary | Configures the primary or virtual terminal line (console or vty values) | os9 | +| ``.exec_timeout`` | string | Configures the EXEC timeout ( values) | os9 | +| ``.exec_banner`` | boolean: true,false\* | Configures the EXEC banner | os9 | +| ``.login_banner`` | boolean: true,false\* | Configures the login banner | os9 | +| ``.motd_banner`` | boolean: true,false\* | Configures the MOTD banner | os9 | +| ``service_passwd_encryption`` | boolean: true,false | Configures system password encryption | os9 | +| ``hash_algo`` | dictionary | Configures hash algorithm commands (see ``hash_algo.*``) | os9 | +| ``hash_algo.algo`` | list | Configures hashing algorithm (see ``algo.*``) | os9 | +| ``algo.name`` | string (required) | Configures the name of the hashing algorithm | os9 | +| ``algo.mode`` | string (required) | Configures the hashing algorithm mode | os9 | +| ``algo.stack_unit`` | integer | Configures the stack-unit for the hashing algorithm | os9 | +| ``algo.port_set`` | integer | Configures the port-pipe set for the hashing algorithm | os9 | +| ``algo.state`` | string: absent,present\* | Deletes the hashing algorithm if set to absent | os9 | +| ``hash_algo.seed`` | list | Configures the hashing algorithm seed (see ``seed.*``) | os9 | +| ``seed.value`` | integer (required) | Configures the hashing algorithm seed value | os9 | +| ``seed.stack_unit`` | integer | Configures the stack-unit for the hashing algorithm seed | os9 | +| ``seed.port_set`` | integer | Configures the port-pipe set for the hashing algorithm seed | os9 | +| ``seed.state`` | string: absent,present\* | Deletes the hashing algorithm seed if set to absent | os9 | +| ``banner`` | dictionary | Configures global banner commands (see ``banner.*``) | os9 | +| ``banner.login`` | dictionary | Configures the login banner (see ``login.*``) | os9 | +| ``login.ack_enable`` | boolean: true,false | Configures positive acknowledgement | os9 | +| ``login.ack_prompt`` | string | Configures the positive acknowledgement prompt | os9 | +| ``login.keyboard_interactive`` | boolean: true,false | Configures the keyboard interactive prompt | os9 | +| ``login.banner_text`` | string | Configures the banner text for the login banner; 'c c' format where 'c' is a delimiting character | os9 | +| ``banner.exec`` | string | Configures the banner text for EXEC process creation banner; 'c c' where 'c' is a delimiting character for os9 | os9 | +| ``banner.motd`` | string | Configures the banner text for the message of the day banner; 'c c' where 'c' is a delimiting character for os9 | os9 | +| ``load_balance`` | dictionary | Configures the global traffic load balance (see ``load_balance.*``) | os9 | +| ``load_balance.ingress_port`` | boolean: true,false | Specifies whether to use the source port ID for the hashing algorithm | os9 | +| ``load_balance.tcp_udp`` | boolean: true, false | Configures whether to use TCP/UDP ports in packets for hashing algorithm | os9 | +| ``load_balance.ip_selection`` | list | Configures IPv4 key fields to use in hashing algorithm; mutually exclusive with *load_balance.tcp_udp* for os9 devices (see ``ip_selection.*``) | os9 | +| ``ip_selection.field`` | string | Configures IPv4 key fields to use in hashing algorithm | os9 | +| ``ip_selection.state`` | string: absent,present\* | Deletes the IPv4 key fields if set to absent | os9 | +| ``load_balance.ipv6_selection`` | list | Configures IPv6 key fields to use in hashing algorithm; mutually exclusive with *load_balance.tcp_udp* for os9 devices (see ``ipv6_selection.*``) | os9 | +| ``ipv6_selection.field`` | string | Configures IPv6 key fields to use in hashing algorithm | os9 | +| ``ipv6_selection.state`` | string: absent,present\* | Deletes the IPv6 key fields if set to absent | os9 | +| ``load_balance.tunnel`` | dictionary | Configures tunnel key fields to use in hashing algorithm (see ``tunnel.*``) | os9 | +| ``tunnel.hash_field`` | list | Configures hash field selection (see ``hash_field.*``) | os9 | +| ``hash_field.name`` | string (required) | Configures the hash field selection | os9 | +| ``hash_field.header`` | string | Configures header for load balance | os9 | +| ``hash_field.state`` | string: absent,present\* | Deletes the hash key selection field if set to absent | os9 | +| ``clock`` | dictionary | Configures time-of-day clock (see ``clock.*``) | os9 | +| ``clock.summer_time`` | dictionary | Configures summer (daylight savings) time (see ``summer_time.*``) | os9 | +| ``summer_time.timezone_name`` | string (required) | Configures the time zone name | os9 | +| ``summer_time.type`` | string (required) | Configures absolute or recurring summer time | os9 | +| ``summer_time.start_datetime`` | string | Configures start datetime; format | os9 | +| ``summer_time.end_datetime`` | string | Configures end datetime; format | os9 | +| ``summer_time.offset_mins`` | integer | Configures offset minutes to add (1 to 1440) | os9 | +| ``summer_time.state`` | string: absent,present\* | Deletes the summer time clock if set to absent | os9 | +| ``clock.timezone`` | dictionary | Configures timezone (see ``timezone.*``) | os9 | +| ``timezone.name`` | string (required) | Configures the timezone name | os9 | +| ``timezone.offset_hours`` | integer | Configures offset hours to add (-23 to 23) | os9 | +| ``timezone.offset_mins`` | integer | Configures offset minutes to add (0 to 59) | os9 | +| ``timezone.state`` | string: absent,present\* | Deletes the time zone if set to absent | os9 | +| ``reload_type`` | dictionary | Configures the reload type (see ``reload_type.*``) | os9 | +| ``reload_type.auto_save`` | boolean: true,false\* | Configures the auto save option for downloaded configuration/script file | os9 | +| ``reload_type.boot_type`` | string: bmp-reload,normal-reload | Configures the boot type | os9 | +| ``reload_type.boot_type_state`` | string: absent,present\* | Deletes the boot type if set to absent | os9 | +| ``reload_type.config_scr_download`` | boolean: true,false\* | Configures whether config/script file needs to be downloaded | os9 | +| ``reload_type.dhcp_timeout`` | integer | Configures DHCP timeout in minutes (0 to 50) | os9 | +| ``reload_type.retry_count`` | integer | Configures the number of retries for image and configuration download (0 to 6) | os9 | +| ``reload_type.relay`` | boolean: true,false\* | Configures the addition of option82 in DHCP client packets | os9 | +| ``reload_type.relay_remote_id`` | string | Configures customize remote ID | os9 | +| ``reload_type.vendor_class_identifier`` | boolean: true,false\* | Configures vendor-class-identifier for DHCP option60 | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +******************** + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_system* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_system role* to completely set the NTP server, hostname, enable password, management route, hash alogrithm, clock, line terminal, banner and reload type. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. The system role writes a simple playbook that only references the *os9_system* role. By including the role, you automatically get access to all of the tasks to configure system features. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_system: + hostname: host1 + unique_hostname: True + enable_password: dell + service_passwd_encryption: true + banner: + exec: t hai t + login: + ack_enable: true + ack_prompt: testbanner + keyboard_interactive: true + banner_text: cloginbannerc + motd: t ansibletest t + hash_algo: + algo: + - name: lag + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + - name: ecmp + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + seed: + - value: 3 + stack_unit: 0 + port_set: 0 + state: present + - value: 2 + state: present + load_balance: + ingress_port: true + ip_selection: + - field: vlan dest-ip + state: present + ipv6_selection: + - field: dest-ipv6 vlan + state: present + tunnel: + hash_field: + - name: mac-in-mac + header: tunnel-header-mac + state: present + clock: + summer_time: + timezone_name: PST + type: date + start_datetime: 2 jan 1993 22:33 + end_datetime: 3 jan 2017 22:33 + offset_mins: 20 + timezone: + name: IST + offset_hours: -5 + offset_mins: 20 + reload_type: + auto_save: true + boot_type: normal-reload + boot_type_state: absent + config_scr_download: true + dhcp_timeout: 5 + retry_count: 3 + relay: true + relay_remote_id: ho + vendor_class_identifier: aa + management_rt: + - ip: 10.16.148.254 + state: present + ipv4: True + line_terminal: + vty 0: + exec_timeout: 40 + exec_banner: true + vty 1: + exec_timeout: 40 200 + motd_banner: true + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_system + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_system/defaults/main.yml b/roles/os9_system/defaults/main.yml new file mode 100644 index 0000000..2892046 --- /dev/null +++ b/roles/os9_system/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_system \ No newline at end of file diff --git a/roles/os9_system/handlers/main.yml b/roles/os9_system/handlers/main.yml new file mode 100644 index 0000000..d19126d --- /dev/null +++ b/roles/os9_system/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_system \ No newline at end of file diff --git a/roles/os9_system/meta/main.yml b/roles/os9_system/meta/main.yml new file mode 100644 index 0000000..e27b534 --- /dev/null +++ b/roles/os9_system/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_system role facilitates the configuration of system attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_system/tasks/main.yml b/roles/os9_system/tasks/main.yml new file mode 100644 index 0000000..336136f --- /dev/null +++ b/roles/os9_system/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating system configuration for os9" + template: + src: os9_system.j2 + dest: "{{ build_dir }}/system9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning system configuration for os9" + os9_config: + src: os9_system.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_system/templates/os9_system.j2 b/roles/os9_system/templates/os9_system.j2 new file mode 100644 index 0000000..594179c --- /dev/null +++ b/roles/os9_system/templates/os9_system.j2 @@ -0,0 +1,422 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# + +Purpose: +Configure system commands for os9 Devices + +os9_system: + hostname: os9 + unique_hostname: true + enable_password: xxxxx + service_passwd_encryption: true + banner: + exec: t hai t + login: + ack_enable: true + ack_prompt: testbanner + keyboard_interactive: true + banner_text: cloginbannerc + motd: t ansibletest t + hash_algo: + algo: + - name: lag + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + - name: ecmp + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + seed: + - value: 3 + stack_unit: 0 + port_set: 0 + state: present + - value: 2 + state: present + load_balance: + ingress_port: true + ip_selection: + - field: vlan dest-ip + state: present + ipv6_selection: + - field: dest-ipv6 vlan + state: present + tunnel: + hash_field: + - name: mac-in-mac + header: tunnel-header-ipv4 + state: present + clock: + summer_time: + timezone_name: PST + type: date + start_datetime: 2 jan 1991 22:33 + end_datetime: 3 jan 2017 22:33 + offset_mins: 20 + timezone: + name: IST + offset_hours: -5 + offset_mins: 20 + reload_type: + auto_save: true + boot_type: normal-reload + config_scr_download: true + dhcp_timeout: 5 + retry_count: 3 + relay: true + relay_remote_id: host + vendor_class_identifier: aa + management_rt: + - ip: 10.16.148.254 + state: present + ipv4: True + line_terminal: + vty 0: + exec_timeout: 40 + exec_banner: true + vty 1: + exec_timeout: 40 200 + motd_banner: true +###################################################} +{% if os9_system is defined and os9_system %} + +{% if os9_system.hostname is defined and os9_system.hostname %} +hostname {{ os9_system.hostname }} +{% endif %} +{% if os9_system %} +{% for key,value in os9_system.items() %} + {% if key == "unique_hostname" %} + {% if value %} +feature unique-name + {% else %} +no feature unique-name + {% endif %} + + {% elif key == "enable_password" %} + {% if value %} +enable password {{ value }} + {% else %} +no enable password + {% endif %} + + {% elif key == "service_passwd_encryption" %} + {% if value %} +service password-encryption + {% else %} +no service password-encryption + {% endif %} + + {% elif key == "clock" and value %} + {% if value.summer_time is defined and value.summer_time %} + {% set time_vars = value.summer_time %} + {% if time_vars.state is defined and time_vars.state == "absent" %} +no clock summer-time + {% else %} + {% if time_vars.timezone_name is defined and time_vars.timezone_name %} + {% if time_vars.type is defined and time_vars.type %} + {% if time_vars.start_datetime is defined and time_vars.start_datetime %} + {% if time_vars.end_datetime is defined and time_vars.end_datetime %} + {% if time_vars.offset_mins is defined and time_vars.offset_mins %} +clock summer-time {{ time_vars.timezone_name }} {{ time_vars.type }} {{ time_vars.start_datetime }} {{ time_vars.end_datetime }} {{ time_vars.offset_mins }} + {% else %} +clock summer-time {{ time_vars.timezone_name }} {{ time_vars.type }} {{ time_vars.start_datetime }} {{ time_vars.end_datetime }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if value.timezone is defined and value.timezone %} + {% set timezone_vars = value.timezone %} + {% if timezone_vars.state is defined and timezone_vars.state == "absent" %} +no clock timezone + {% else %} + {% if timezone_vars.name is defined and timezone_vars.name %} + {% if timezone_vars.offset_hours is defined and timezone_vars.offset_hours %} + {% if timezone_vars.offset_mins is defined and timezone_vars.offset_mins %} +clock timezone {{ timezone_vars.name }} {{ timezone_vars.offset_hours }} {{ timezone_vars.offset_mins }} + {% else %} +clock timezone {{ timezone_vars.name }} {{ timezone_vars.offset_hours }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + + + {% elif key == "hash_algo" and value %} + {% if value.algo is defined and value.algo %} + {% for item in value.algo %} + {% if item.name is defined and item.name %} + {% if item.mode is defined and item.mode %} + {% if item.state is defined and item.state == "absent" %} + {% if item.stack_unit is defined and item.stack_unit >= 0 %} + {% if item.port_set is defined and item.port_set >= 0 %} +no hash-algorithm {{ item.name }} {{ item.mode }} stack-unit {{ item.stack_unit }} port-set {{ item.port_set }} + {% else %} +no hash-algorithm {{ item.name }} {{ item.mode }} stack-unit {{ item.stack_unit }} + {% endif %} + {% else %} +no hash-algorithm {{ item.name }} {{ item.mode }} + {% endif %} + {% else %} + {% if item.stack_unit is defined and item.stack_unit >= 0 %} + {% if item.port_set is defined and item.port_set >= 0 %} +hash-algorithm {{ item.name }} {{ item.mode }} stack-unit {{ item.stack_unit }} port-set {{ item.port_set }} + {% else %} +hash-algorithm {{ item.name }} {{ item.mode }} stack-unit {{ item.stack_unit }} + {% endif %} + {% else %} +hash-algorithm {{ item.name }} {{ item.mode }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if value.seed is defined and value.seed %} + {% for item in value.seed %} + {% if item.value is defined and item.value >= 0 %} + {% if item.state is defined and item.state == "absent" %} + {% if item.stack_unit is defined and item.stack_unit >= 0 %} + {% if item.port_set is defined and item.port_set >= 0 %} +no hash-algorithm seed {{ item.value }} stack-unit {{ item.stack_unit }} port-set {{ item.port_set }} + {% else %} +no hash-algorithm seed {{ item.value }} stack-unit {{ item.stack_unit }} + {% endif %} + {% else %} +no hash-algorithm seed {{ item.value }} + {% endif %} + {% else %} + {% if item.stack_unit is defined and item.stack_unit >= 0 %} + {% if item.port_set is defined and item.port_set >= 0 %} +hash-algorithm seed {{ item.value }} stack-unit {{ item.stack_unit }} port-set {{ item.port_set }} + {% else %} +hash-algorithm seed {{ item.value }} stack-unit {{ item.stack_unit }} + {% endif %} + {% else %} +hash-algorithm seed {{ item.value }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% elif key == "banner" and value %} + {% if value.exec is defined %} + {% if value.exec %} +banner exec {{ value.exec }} + {% else %} +no banner exec + {% endif %} + {% endif %} + {% if value.motd is defined %} + {% if value.motd %} +banner motd {{ value.motd }} + {% else %} +no banner motd + {% endif %} + {% endif %} + {% if value.login is defined and value.login %} + {% set login_vars = value.login %} + {% if login_vars.ack_enable is defined %} + {% if login_vars.ack_enable %} +banner login acknowledgment enable + {% else %} +no banner login acknowledgment enable + {% endif %} + {% endif %} + {% if login_vars.ack_prompt is defined %} + {% if login_vars.ack_prompt %} +banner login acknowledgment prompt {{ login_vars.ack_prompt }} + {% else %} +no banner login acknowledgment prompt + {% endif %} + {% endif %} + {% if login_vars.keyboard_interactive is defined %} + {% if login_vars.keyboard_interactive %} +banner login keyboard-interactive + {% else %} +no banner login keyboard-interactive + {% endif %} + {% endif %} + {% if login_vars.banner_text is defined %} + {% if login_vars.banner_text %} +banner login {{ login_vars.banner_text }} + {% else %} +no banner login + {% endif %} + {% endif %} + {% endif %} + {% elif key == "load_balance" and value %} + {% if value.ingress_port is defined %} + {% if value.ingress_port %} +load-balance ingress-port enable + {% else %} +no load-balance ingress-port enable + {% endif %} + {% endif %} + {% if value.tcp_udp is defined %} + {% if value.tcp_udp %} +load-balance tcp-udp enable + {% else %} +no load-balance tcp-udp enable + {% endif %} + {% endif %} + {% if value.ip_selection is defined and value.ip_selection %} + {% for item in value.ip_selection %} + {% if item.field is defined and item.field %} + {% if item.state is defined and item.state == "absent" %} +no load-balance ip-selection + {% else %} +load-balance ip-selection {{ item.field }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if value.ipv6_selection is defined and value.ipv6_selection %} + {% for item in value.ipv6_selection %} + {% if item.field is defined and item.field %} + {% if item.state is defined and item.state == "absent" %} +no load-balance ipv6-selection + {% else %} +load-balance ipv6-selection {{ item.field }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if value.tunnel is defined and value.tunnel %} + {% set tunnel_vars = value.tunnel %} + {% if tunnel_vars.hash_field is defined and tunnel_vars.hash_field %} + {% for item in tunnel_vars.hash_field %} + {% if item.name is defined and item.name %} + {% if item.header is defined and item.header %} + {% if item.state is defined and item.state == "absent" %} +no load-balance tunnel {{ item.name }} {{ item.header }} + {% else %} +load-balance tunnel {{ item.name }} {{ item.header }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + + {% elif key == "reload_type" and value %} +reload-type + {% if value.auto_save is defined %} + {% if value.auto_save %} + auto-save enable + {% else %} + auto-save disable + {% endif %} + {% endif %} + {% if value.boot_type is defined and value.boot_type %} + {% if boot_type_state is defined and boot_type_state =="absent" %} + no boot-type {{ value.boot_type }} + {% else %} + boot-type {{ value.boot_type }} + {% endif %} + {% endif %} + {% if value.config_scr_download is defined %} + {% if value.config_scr_download %} + config-scr-download enable + {% else %} + config-scr-download disable + {% endif %} + {% endif %} + {% if value.dhcp_timeout is defined %} + {% if value.dhcp_timeout >=0 %} + dhcp-timeout {{ value.dhcp_timeout }} + {% else %} + no dhcp-timeout 0 + {% endif %} + {% endif %} + {% if value.retry_count is defined %} + {% if value.retry_count >=0 %} + retry-count {{ value.retry_count }} + {% else %} + no retry-count 0 + {% endif %} + {% endif %} + {% if value.relay is defined %} + {% if value.relay %} + relay enable + {% else %} + relay disable + {% endif %} + {% endif %} + {% if value.relay_remote_id is defined %} + {% if value.relay_remote_id %} + relay remote-id {{ value.relay_remote_id }} + {% else %} + no relay remote-id a + {% endif %} + {% endif %} + {% if value.vendor_class_identifier is defined %} + {% if value.vendor_class_identifier %} + vendor-class-identifier {{ value.vendor_class_identifier }} + {% else %} + no vendor-class-identifier a + {% endif %} + {% endif %} + + {% elif key == "management_rt" and value %} + {% for item in value %} + {% if item.ip is defined and item.ip %} + {% if item.ipv4 is defined and item.ipv4 %} + {% if item.state is defined and item.state == "absent" %} +no management route 0.0.0.0/0 {{ item.ip }} + {% else %} +management route 0.0.0.0/0 {{ item.ip }} + {% endif %} + {% else %} + {% if item.state is defined and item.state == "absent" %} +no management route ::/0 {{ item.ip }} + {% else %} +management route ::/0 {{ item.ip }} + {% endif %} + {% endif%} + {% endif %} + {% endfor %} + + {% elif key == "line_terminal" and value %} + {% for key in value.keys() %} + {% set vty_vars = value[key] %} +line {{ key }} + {% if vty_vars.exec_timeout is defined %} + {% if vty_vars.exec_timeout %} + {% set timeout = (vty_vars.exec_timeout | string).split(" ") %} + {% if timeout | length > 1 %} + exec-timeout {{ vty_vars.exec_timeout }} + {% else %} + exec-timeout {{ vty_vars.exec_timeout }} 0 + {% endif %} + {% else %} + no exec-timeout + {% endif %} + {% endif %} + {% if vty_vars.exec_banner is defined %} + {% if vty_vars.exec_banner %} + exec-banner + {% else %} + no exec-banner + {% endif %} + {% endif %} + {% if vty_vars.motd_banner is defined %} + {% if vty_vars.motd_banner %} + motd-banner + {% else %} + no motd-banner + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + +{% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_system/tests/inventory.yaml b/roles/os9_system/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_system/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_system/tests/main.os9.yaml b/roles/os9_system/tests/main.os9.yaml new file mode 100644 index 0000000..474f282 --- /dev/null +++ b/roles/os9_system/tests/main.os9.yaml @@ -0,0 +1,74 @@ +--- +# vars file for dellemc.os9.os9_system, +# below gives a sample configuration +# Sample variables for OS9 device +os9_system: + hostname: os9 + enable_password: calvin + line_terminal: + vty 0: + exec_timeout: 40 + vty 1: + exec_timeout: 40 200 + service_passwd_encryption: true + banner: + exec: t hai t + login: + ack_enable: true + ack_prompt: testbanner + keyboard_interactive: true + banner_text: cloginbannerc + motd: t ansibletest t + hash_algo: + algo: + - name: lag + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + - name: ecmp + mode: xor1 + stack_unit: 0 + port_set: 0 + state: present + seed: + - value: 3 + stack_unit: 0 + port_set: 0 + state: present + - value: 2 + state: present + load_balance: + ingress_port: true + ip_selection: + - field: vlan dest-ip + state: present + ipv6_selection: + - field: dest-ipv6 vlan + state: present + tunnel: + hash_field: + - name: mac-in-mac + header: tunnel-header-mac + state: present + clock: + summer_time: + timezone_name: PST + type: date + start_datetime: 2 jan 1993 22:33 + end_datetime: 3 jan 2017 22:33 + offset_mins: 20 + timezone: + name: IST + offset_hours: -5 + offset_mins: 20 + reload_type: + auto_save: true + boot_type: normal-reload + boot_type_state: absent + config_scr_download: true + dhcp_timeout: 5 + retry_count: 3 + relay: true + relay_remote_id: ho + vendor_class_identifier: aa \ No newline at end of file diff --git a/roles/os9_system/tests/test.yaml b/roles/os9_system/tests/test.yaml new file mode 100644 index 0000000..4d14222 --- /dev/null +++ b/roles/os9_system/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_system \ No newline at end of file diff --git a/roles/os9_system/vars/main.yml b/roles/os9_system/vars/main.yml new file mode 100644 index 0000000..f056f57 --- /dev/null +++ b/roles/os9_system/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_system \ No newline at end of file diff --git a/roles/os9_users/LICENSE b/roles/os9_users/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_users/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_users/README.md b/roles/os9_users/README.md new file mode 100644 index 0000000..27ecd53 --- /dev/null +++ b/roles/os9_users/README.md @@ -0,0 +1,110 @@ +Users role +========== + +This role facilitates the configuration of global system user attributes. It supports the configuration of CLI users, and is abstracted for Dell EMC platforms running OS9. + +The users role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_users list keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``userrole`` | stirng (required) | Configures the role name which can be configured for users | os9 | +| ``userrole_state`` | string: absent,present\* | Deletes the user role with specified name if set to absent | os9 | +| ``username`` | string (required) | Configures the username which must adhere to specific format guidelines (valid usernames begin with A-Z, a-z, or 0-9 and can also contain `@#$%^&*-_= +;<>,.~` characters) | os9 | +| ``password`` | string | Configures the password set for the username; | os9 | +| ``role`` | string | Configures the role assigned to the user | os9 | +| ``privilege`` | int | Configures the privilege level for the user; integers between 0 and 15 for os9 devices; if this key is ommitted, the default privilege is 1 for both os9 | os9 | +| ``access_class`` | string | Configures the access-class for the user | os9 | +| ``pass_key`` | integer: 0\*,7 | Configures the password as encrypted if set to 7 in os9 devices | os9 | +| ``secret`` | string | Configures line password as secret in os9 devices | os9 | +| ``secret_key`` | integer: 0\*,5 | Configures the secret line password using md5 encrypted algorithm | os9 | +| ``state`` | string: absent,present\* | Deletes a user account if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_users* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file. It writes a simple playbook that only references the *os9_users* role. By including the role, you automatically get access to all of the tasks to configure user features. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_users: + - userrole: role1 + userrole_state: present + - username: u1 + password: test + role: sysadmin + privilege: 0 + state: absent + - username: u1 + password: false + privilege: 1 + access_class: a1 + role: netadmin + state: present + - username: u2 + secret: test1 + secret_key : 0 + access_class: a2 + privilege: 3 + role: sysadmin + state: present + +**Simple playbook to setup users - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_users + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_users/defaults/main.yml b/roles/os9_users/defaults/main.yml new file mode 100644 index 0000000..b077038 --- /dev/null +++ b/roles/os9_users/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_users \ No newline at end of file diff --git a/roles/os9_users/handlers/main.yml b/roles/os9_users/handlers/main.yml new file mode 100644 index 0000000..0b43979 --- /dev/null +++ b/roles/os9_users/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_users \ No newline at end of file diff --git a/roles/os9_users/meta/main.yml b/roles/os9_users/meta/main.yml new file mode 100644 index 0000000..d8ea90f --- /dev/null +++ b/roles/os9_users/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_users role facilitates the configuration of user attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_users/tasks/main.yml b/roles/os9_users/tasks/main.yml new file mode 100644 index 0000000..18a635b --- /dev/null +++ b/roles/os9_users/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating users configuration for os9" + template: + src: os9_users.j2 + dest: "{{ build_dir }}/users9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning users configuration for os9" + os9_config: + src: os9_users.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_users/templates/os9_users.j2 b/roles/os9_users/templates/os9_users.j2 new file mode 100644 index 0000000..45c04bd --- /dev/null +++ b/roles/os9_users/templates/os9_users.j2 @@ -0,0 +1,141 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{############################################# +Purpose: +Configure users commands for os9 Devices +os9_users: + - userrole: role1 + userrole_state: present + userrole_inherit: rolename + - username: test + password: test + pass_key: 7 + access_class: a1 + role: sysadmin + privilege: 0 + state: present + - username: u1 + password: false + privilege: 1 + access_class: a1 + role: netadmin + state: present + - username: u2 + secret: test1 + secret_key : 0 + access_class: a2 + privilege: 3 + role: sysadmin + state: present +###################################################} +{% if os9_users is defined and os9_users %} +{% for item in os9_users %} + {% if item.userrole is defined and item.userrole %} + {% if item.userrole_state is defined and item.userrole_state == "absent" %} + {% for item in os9_users %} + {% if item.username is defined and item.username %} + {% if item.state is defined and item.state == "absent" %} +no username {{ item.username }} + {% endif %} + {% endif %} + {% endfor %} +no userrole {{ item.userrole }} + {% else %} + {% if item.userrole_inherit is defined and item.userrole_inherit %} +userrole {{ item.userrole }} inherit {{ item.userrole_inherit }} + {% else %} +userrole {{ item.userrole }} + {% endif %} + {% endif %} + {% endif %} + {% if item.role_permission is defined and item.role_permission %} + {% if item.role_permission.mode is defined and (item.role_permission.mode == "configure" or item.role_permission.mode == "exec" or item.role_permission.mode == "interface" or item.role_permission.mode == "line" or item.role_permission.mode == "route-map" or item.role_permission.mode == "router") %} + {% if item.role_permission.action is defined and (item.role_permission.action == "reset" or item.role_permission.action == "addrole" or item.role_permission.action == "deleterole") %} + {% if item.role_permission.line is defined and item.role_permission.line %} + {% if item.role_permission.action != "reset" and item.role_permission.role_name is defined and item.role_permission.role_name %} + {% if item.role_permission.state is defined and item.role_permission.state == "absent" %} +norole {{ item.role_permission.mode }} {{ item.role_permission.action }} {{ item.role_permission.role_name }} {{ item.role_permission.line }} + {% else %} +role {{ item.role_permission.mode }} {{ item.role_permission.action }} {{ item.role_permission.role_name }} {{ item.role_permission.line }} + {% endif %} + {% else %} +role {{ item.role_permission.mode }} reset {{ item.role_permission.line }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if item.username is defined and item.username %} + {% if item.state is defined and item.state == "absent" %} +no username {{ item.username }} + {% else %} + {% if item.password is defined and item.password %} + {% if item.pass_key is defined and item.pass_key %} +{% set passwd = item.pass_key|string+" "+item.password %} + {% else %} +{% set passwd = item.password %} + {% endif %} + {% if item.privilege is defined and item.privilege and item.access_class is defined and item.access_class and item.role is defined and item.role %} +username {{ item.username }} password {{ passwd }} privilege {{ item.privilege }} role {{ item.role }} access-class {{ item.access_class }} + {% elif item.role is defined and item.role and item.privilege is defined and item.privilege %} +username {{ item.username }} password {{ passwd }} privilege {{ item.privilege }} role {{ item.role }} + {% elif item.role is defined and item.role and item.access_class is defined and item.access_class %} +username {{ item.username }} password {{ passwd }} access-class {{ item.access_class }} role {{ item.role }} + {% elif item.privilege is defined and item.privilege and item.access_class is defined and item.access_class %} +username {{ item.username }} password {{ passwd }} access-class {{ item.access_class }} privilege {{ item.privilege }} + {% elif item.role is defined and item.role %} +username {{ item.username }} password {{ passwd }} role {{ item.role }} + {% elif item.privilege is defined and item.privilege %} +username {{ item.username }} password {{ passwd }} privilege {{ item.privilege }} + {% elif item.access_class is defined and item.access_class %} +username {{ item.username }} password {{ passwd }} access-class {{ item.access_class }} + {% else %} +username {{ item.username }} password {{ passwd }} + {% endif %} + {% elif item.secret is defined and item.secret %} + {% if item.secret_key is defined and item.secret_key %} +{% set passwd = item.secret_key|string+" " +item.secret %} + {% else %} +{% set passwd = item.secret %} + {% endif %} + {% if item.privilege is defined and item.privilege and item.access_class is defined and item.access_class and item.role is defined and item.role %} +username {{ item.username }} secret {{ passwd }} role {{ item.role }} privilege {{ item.privilege }} access-class {{ + item.access_class }} + {% elif item.role is defined and item.role and item.privilege is defined and item.privilege %} +username {{ item.username }} secret {{ passwd }} role {{ item.role }} privilege {{ item.privilege }} + {% elif item.role is defined and item.role and item.access_class is defined and item.access_class %} +username {{ item.username }} secret {{ passwd }} role {{ item.role }} access-class {{ item.access_class }} + {% elif item.privilege is defined and item.privilege and item.access_class is defined and item.access_class %} +username {{ item.username }} secret {{ passwd }} privilege {{ item.privilege }} access-class {{ item.access_class }} + {% elif item.role is defined and item.role %} +username {{ item.username }} secret {{ passwd }} role {{ item.role }} + {% elif item.privilege is defined and item.privilege %} +username {{ item.username }} secret {{ passwd }} privilege {{ item.privilege }} + {% elif item.access_class is defined and item.access_class %} +username {{ item.username }} secret {{ passwd }} access-class {{ item.access_class }} + {% else %} +username {{ item.username }} secret {{ passwd }} + {% endif %} + {% else %} + {% if item.privilege is defined and item.privilege and item.access_class is defined and item.access_class and item.role is defined and item.role %} +username {{ item.username }} nopassword role {{ item.role }} privilege {{ item.privilege }} access-class {{ item.access_class }} + {% elif item.role is defined and item.role and item.privilege is defined and item.privilege %} +username {{ item.username }} nopassword role {{ item.role }} privilege {{ item.privilege }} + {% elif item.role is defined and item.role and item.access_class is defined and item.access_class %} +username {{ item.username }} nopassword role {{ item.role }} access-class {{ item.access_class }} + {% elif item.privilege is defined and item.privilege and item.access_class is defined and item.access_class %} +username {{ item.username }} nopassword privilege {{ item.privilege }} access-class {{ item.access_class }} + {% elif item.role is defined and item.role %} +username {{ item.username }} nopassword role {{ item.role }} + {% elif item.privilege is defined and item.privilege %} +username {{ item.username }} nopassword privilege {{ item.privilege }} + {% elif item.access_class is defined and item.access_class %} +username {{ item.username }} nopassword access-class {{ item.access_class }} + {% else %} +username {{ item.username }} nopassword + {% endif %} + + {% endif %} + {% endif %} + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_users/tests/inventory.yaml b/roles/os9_users/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_users/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_users/tests/main.os9.yaml b/roles/os9_users/tests/main.os9.yaml new file mode 100644 index 0000000..fb0c0b8 --- /dev/null +++ b/roles/os9_users/tests/main.os9.yaml @@ -0,0 +1,27 @@ +--- +# vars file for dellemc.os9.os9_users, +# below gives a sample configuration +# Sample variables for OS9 device +os9_users: + - userrole: role1 + userrole_state: present + - username: test + password: test + pass_key: 7 + access_class: a1 + role: role1 + privilege: 0 + state: present + - username: u1 + password: false + privilege: 1 + access_class: a1 + role: netadmin + state: present + - username: u2 + secret: test1 + secret_key: 0 + access_class: a2 + privilege: 3 + role: sysadmin + state: present \ No newline at end of file diff --git a/roles/os9_users/tests/test.yaml b/roles/os9_users/tests/test.yaml new file mode 100644 index 0000000..1e26491 --- /dev/null +++ b/roles/os9_users/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_users \ No newline at end of file diff --git a/roles/os9_users/vars/main.yml b/roles/os9_users/vars/main.yml new file mode 100644 index 0000000..05fc40b --- /dev/null +++ b/roles/os9_users/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_users \ No newline at end of file diff --git a/roles/os9_vlan/LICENSE b/roles/os9_vlan/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_vlan/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_vlan/README.md b/roles/os9_vlan/README.md new file mode 100644 index 0000000..b0c15be --- /dev/null +++ b/roles/os9_vlan/README.md @@ -0,0 +1,110 @@ +VLAN role +========= + +This role facilitates configuring virtual LAN (VLAN) attributes. It supports the creation and deletion of a VLAN and its member ports. This role is abstracted for Dell EMC platforms running OS9. + +The VLAN role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables. + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- For variables with no state variable, setting an empty value for the variable negates the corresponding configuration +- *os9_vlan* (dictionary) holds the key with the VLAN ID key and default-vlan key. +- VLAN ID key should be in format "vlan " (1 to 4094) +- Variables and values are case-sensitive + +**os9_vlan** + +| Key | Type | Notes | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``default_vlan`` | boolean | Configures the default VLAN feature as diabled if set to true | os9 | + +**VLAN ID keys** + +| Key | Type | Notes | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``name`` | string | Configures the name of the VLAN | os9 | +| ``description`` | string | Configures a single line description for the VLAN | os9 | +| ``tagged_members`` | list | Specifies the list of port members to be tagged to the corresponding VLAN (see ``tagged_members.*``) | os9 | +| ``tagged_members.port`` | string | Specifies valid device interface names to be tagged for each VLAN | os9 | +| ``tagged_members.state`` | string: absent,present | Deletes the tagged association for the VLAN if set to absent | os9 | +| ``untagged_members`` | list | Specifies the list of port members to be untagged to the corresponding VLAN (see ``untagged_members.*``) | os9 | +| ``untagged_members.port`` | string | Specifies valid device interface names to be untagged for each VLAN | os9 | +| ``untagged_members.state`` | string: absent,present | Deletes the untagged association for the VLAN if set to absent | os9 | +| ``state`` | string: absent,present\* | Deletes the VLAN corresponding to the ID if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars directories* or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_vlan* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +## Example playbook + +This example uses the *os9_vlan* role to setup the VLAN ID and name, and it configures tagged and untagged port members for the VLAN. You can also delete the VLAN with the ID or delete the members associated to it. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the os9_vlan role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_vlan: + default_vlan: true + vlan 100: + name: "Mgmt Network" + description: "Int-vlan" + tagged_members: + - port: fortyGigE 1/30 + state: absent + untagged_members: + - port: fortyGigE 1/14 + state: present + state: present + + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_vlan + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_vlan/defaults/main.yml b/roles/os9_vlan/defaults/main.yml new file mode 100644 index 0000000..2e62ad6 --- /dev/null +++ b/roles/os9_vlan/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_vlan \ No newline at end of file diff --git a/roles/os9_vlan/handlers/main.yml b/roles/os9_vlan/handlers/main.yml new file mode 100644 index 0000000..93bec0d --- /dev/null +++ b/roles/os9_vlan/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_vlan \ No newline at end of file diff --git a/roles/os9_vlan/meta/main.yml b/roles/os9_vlan/meta/main.yml new file mode 100644 index 0000000..5c9da37 --- /dev/null +++ b/roles/os9_vlan/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_vlan role facilitates the configuration of VLAN attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_vlan/tasks/main.yml b/roles/os9_vlan/tasks/main.yml new file mode 100644 index 0000000..d10315d --- /dev/null +++ b/roles/os9_vlan/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating VLAN configuration for os9" + template: + src: os9_vlan.j2 + dest: "{{ build_dir }}/vlan9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning VLAN configuration for os9" + os9_config: + src: os9_vlan.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_vlan/templates/os9_vlan.j2 b/roles/os9_vlan/templates/os9_vlan.j2 new file mode 100644 index 0000000..e9da9e5 --- /dev/null +++ b/roles/os9_vlan/templates/os9_vlan.j2 @@ -0,0 +1,79 @@ +#jinja2: trim_blocks: True, lstrip_blocks: True +{########################################## +Purpose: +Configure VLAN Interface commands for os9 Devices +os9_vlan: + default_vlan: true + VLAN 1: + name: "vlan2" + description: "int-vlan" + tagged_members: + - port: fortyGigE 0/32 + state: present + - port: fortyGigE 0/40 + state: absent + untagged_members: + - port: fortyGigE 0/92 + state: absent + - port: fortyGigE 0/44 + state: present + state: present +#########################################} +{% if os9_vlan is defined and os9_vlan %} +{% for key,value in os9_vlan.items() %} + {% if key == "default_vlan" %} + {% if value %} +default-vlan disable + {% else %} +no default-vlan disable + {% endif %} + {% else %} + + {% set vlan_id = key.split(" ") %} + {% set vlan_vars = os9_vlan[key] %} + {% if vlan_vars.state is defined and vlan_vars.state == "absent" %} +no interface Vlan {{ vlan_id[1] }} + {% else %} +interface Vlan {{ vlan_id[1] }} + {% if vlan_vars.name is defined%} + {% if vlan_vars.name %} + name {{ vlan_vars.name }} + {% else %} + no name + {% endif %} + {% endif %} + {% if vlan_vars.description is defined %} + {% if vlan_vars.description %} + description {{ vlan_vars.description }} + {% else %} + no description + {% endif %} + {% endif %} + {% if vlan_vars.untagged_members is defined %} + {% for ports in vlan_vars.untagged_members %} + {% if ports.port is defined and ports.port %} + {% if ports.state is defined and ports.state == "absent" %} + no untagged {{ ports.port }} + {% else %} + untagged {{ ports.port }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% if vlan_vars.tagged_members is defined %} + {% for ports in vlan_vars.tagged_members %} + {% if ports.port is defined and ports.port %} + {% if ports.state is defined and ports.state == "absent" %} + no tagged {{ ports.port }} + {% else %} + tagged {{ ports.port }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_vlan/tests/inventory.yaml b/roles/os9_vlan/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_vlan/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_vlan/tests/main.os9.yaml b/roles/os9_vlan/tests/main.os9.yaml new file mode 100644 index 0000000..7f74b3b --- /dev/null +++ b/roles/os9_vlan/tests/main.os9.yaml @@ -0,0 +1,20 @@ +--- +# vars file for dellemc.os9.os9_vlan, +# below gives a example configuration +# Sample variables for OS9 device +os9_vlan: + default_vlan: true + vlan 100: + name: "Blue Network" + description: "Interface-vlan" + tagged_members: + - port: fortyGigE 1/2 + state: present + - port: fortyGigE 1/11 + state: present + untagged_members: + - port: fortyGigE 1/3 + state: present + - port: fortyGigE 1/10 + state: present + state: present \ No newline at end of file diff --git a/roles/os9_vlan/tests/test.yaml b/roles/os9_vlan/tests/test.yaml new file mode 100644 index 0000000..1dfd42b --- /dev/null +++ b/roles/os9_vlan/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_vlan \ No newline at end of file diff --git a/roles/os9_vlan/vars/main.yml b/roles/os9_vlan/vars/main.yml new file mode 100644 index 0000000..cd2ceef --- /dev/null +++ b/roles/os9_vlan/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_vlan \ No newline at end of file diff --git a/roles/os9_vlt/LICENSE b/roles/os9_vlt/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_vlt/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_vlt/README.md b/roles/os9_vlt/README.md new file mode 100644 index 0000000..775e72e --- /dev/null +++ b/roles/os9_vlt/README.md @@ -0,0 +1,138 @@ +VLT role +======== + +This role facilitates the configuration of the basics of virtual link trunking (VLT) to provide a loop-free topology. This role is abstracted for Dell EMC platform running OS9. + +The VLT role requires an SSH connection for connectivity to your Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**os9_vlt keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``domain`` | integer (required) | Configures the VLT domain identification number (1 to 1000) | os9 | +| ``backup_destination`` | string | Configures an IPv4 address for the VLT backup link (A.B.C.D format or X:X:X:X::X format) | os9 | +| ``destination_type`` | string | Configures the backup destination based on this destination type (IPv4 or IPv6)| os9 | +| ``backup_destination_vrf`` | string | Configures the virtual routing and forwarding (VRF) instance through which the backup destination IP is reachable (*vrfname* must be present) | os9| +| ``VLTi`` | integer | Configures the peer link port-channel ID for the VLT domain (1 to 4096) | os9 | +| ``peer_routing`` | boolean | Configures VLT peer routing | os9 | +| ``peer_routing_timeout`` | integer | Configures the timeout for peer routing (1 to 65535)| os9 | +| ``multicast_peer_routing_timeout`` | integer | Configures the timeout for multicast peer routing (1 to 1200) | os9 | +| ``priority`` | integer | Configures the primary priority to the corresponding channel ID | os9 | +| ``unit_id`` | integer | Configures the system unit ID for VLT (either 0 or 1) | os9 | +| ``vlt_mac`` | string | Configures the VLT MAC address | os9 | +| ``vlt_peers`` | dictionary | Contains objects to configure the VLT peer port-channel (see ``vlt_peers.*``) | os9 | +| ``vlt_peers.`` | dictionary | Configures the VLT peer port-channel (`Po value`) | os9 | +| ``vlt_peers..peer_lag`` | integer | Configures the port-channel ID of the VLT peer lag | os9 | +| ``system_mac`` | string | Configures the system MAC address for VLT | os9 | +| ``delay_restore`` | integer | Configures the delay in bringing up VLT ports after reload or peer-link restoration (default 90)| os9 | +| ``delay_restore_abort_threshold`` | integer | Configures the wait interval for VLT delay-restore timer to abort (default 60) | os9 | +| ``proxy_gateway`` | dictionary | Contains objects to configure the VLT proxy gateway (see ``proxy_gateway.*``) | os9 | +| ``proxy_gateway.static`` | dictionary | Contains objects to configure the static VLT proxy gateway (see ``static.*``) | os9 | +| ``static.remote_mac`` | list | Configures the remote MAC for static VLT proxy gateway (see ``remote_mac.*``) | os9 | +| ``remote_mac.address`` | string | Configures the remote MAC address for the static VLT proxy gateway | os9 | +| ``remote_mac.exclude_vlan_range`` | string | Configures the exclude VLAN for the static VLT proxy gateway | os9 | +| ``remote_mac.state`` | string: absent,present | Deletes the remote MAC address or exclude VLAN configured on the proxy gateway if set to absent | os9 | +| ``static.proxy_static_state`` | string: absent,present | Deletes the static VLT proxy gateway if set to absent | os9 | +| ``proxy_gateway.lldp`` | dictionary | Contains objects to configure LLDP VLT proxy gateway (see ``lldp.*`` for each item); mutually exclusive with *proxy_gateway.static* | os9 | +| ``lldp.peer_domain_link`` | list | Configures the VLT proxy gateway interface (see ``peer_domain_link.*``) | os9 | +| ``peer_domain_link.port_channel_id`` | integer | Configures the port-channel for the VLT proxy gateway | os9 | +| ``peer_domain_link.exclude_vlan_range`` | string | Configures to exclude VLAN for LLDP VLT proxy gateway | os9 | +| ``peer_domain_link.state`` | string: absent,present | Deletes the port-channel or exclude VLAN configured on the proxy gateway if set to absent | os9 | +| ``lldp.proxy_lldp_state`` | string: absent,present | Deletes the LLDP VLT proxy gateway if set to absent | os9 | +| ``lldp.vlt_peer_mac`` | boolean | Configures the proxy gateway transmit for square VLT | os9 | +| ``lldp.peer_timeout`` | integer | Configures the proxy gateway restore timer (1 to 65535) | os9 | +| ``state`` | string: absent,present | Deletes the VLT instance if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking OS roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory, or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_vlt* role is built on modules included in the core Ansible code. These modules were added in ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_vlt* role to setup a VLT-domain. It creates a *hosts* file with the switch details and corresponding variables.The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_vlt* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + os9_vlt: + domain: 1 + backup_destination: 192.168.1.1 + destination_type: "ipv4" + priority: 1 + VLTi: 101 + backup_destination_vrf: VLTi-KEEPALIVE + peer_routing: true + peer_routing_timeout: 200 + multicast_peer_routing_timeout: 250 + unit_id: 0 + system_mac: aa:aa:aa:aa:aa:aa + delay_restore: 100 + delay_restore_abort_threshold: 110 + proxy_gateway: + static: + remote_mac: + - address: aa:aa:aa:aa:aa:aa + exclude_vlan_range: 2 + state: present + proxy_static_state: present + vlt_peers: + Po 12: + peer_lag: 13 + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_vlt + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_vlt/defaults/main.yml b/roles/os9_vlt/defaults/main.yml new file mode 100644 index 0000000..7d2e3ec --- /dev/null +++ b/roles/os9_vlt/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_vlt \ No newline at end of file diff --git a/roles/os9_vlt/handlers/main.yml b/roles/os9_vlt/handlers/main.yml new file mode 100644 index 0000000..703bdba --- /dev/null +++ b/roles/os9_vlt/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_vlt \ No newline at end of file diff --git a/roles/os9_vlt/meta/main.yml b/roles/os9_vlt/meta/main.yml new file mode 100644 index 0000000..ff1cf33 --- /dev/null +++ b/roles/os9_vlt/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_vlt role facilitates the configuration of VLT attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_vlt/tasks/main.yml b/roles/os9_vlt/tasks/main.yml new file mode 100644 index 0000000..61de03d --- /dev/null +++ b/roles/os9_vlt/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating VLT configuration for os9" + template: + src: os9_vlt.j2 + dest: "{{ build_dir }}/vlt9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning VLT configuration for os9" + os9_config: + src: os9_vlt.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_vlt/templates/os9_vlt.j2 b/roles/os9_vlt/templates/os9_vlt.j2 new file mode 100644 index 0000000..6dd6303 --- /dev/null +++ b/roles/os9_vlt/templates/os9_vlt.j2 @@ -0,0 +1,217 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################ +Purpose: +Configure VLT commands for os9 Devices. +os9_vlt: + domain: 1 + backup_destination: 192.168.1.1 + destination_type: ipv4 + priority: 1 + VLTi: 101 + backup_destination_vrf: VLTi-KEEPALIVE + unit_id: 0 + peer_routing: True + peer_routing_timeout: 200 + multicast_peer_routing_timeout: 300 + vlt_peers: + Po 12: + peer_lag: 13 + system_mac: aa:aa:aa:aa:aa:aa + delay_restore: 100 + delay_restore_abort_threshold: 110 + proxy_gateway: + static: + remote_mac: + - address: aa:aa:aa:aa:aa:aa + exclude_vlan_range: 2 + state: present + proxy_static_state: present + lldp: + vlt_peer_mac: true + peer_timeout: 20 + peer_domain_link: + - port_channel_id: 10 + exclude_vlan_range: 3 + state: present + proxy_lldp_state: present + + state: present +################################} +{% if os9_vlt is defined and os9_vlt %} + {% if os9_vlt.vlt_peers is defined and os9_vlt.vlt_peers %} + {% for key in os9_vlt.vlt_peers.keys() %} + {% set channel_id = key.split(" ") %} + {% set peer_vars = os9_vlt.vlt_peers[key] %} +interface Port-channel {{ channel_id[1] }} + {% if peer_vars.peer_lag is defined %} + {% if peer_vars.peer_lag %} + vlt-peer-lag port-channel {{ peer_vars.peer_lag}} + {% else %} + no vlt-peer-lag + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if os9_vlt.domain is defined and os9_vlt.domain %} + {% if os9_vlt.state is defined and os9_vlt.state == 'absent' %} +no vlt domain {{ os9_vlt.domain }} + {% else %} +vlt domain {{ os9_vlt.domain }} + {% if os9_vlt.backup_destination is defined %} + {% if os9_vlt.backup_destination %} + {% if os9_vlt.destination_type is defined %} + {% if os9_vlt.destination_type == 'ipv6' %} + back-up destination ipv6 {{ os9_vlt.backup_destination }} + {% elif os9_vlt.destination_type == 'ipv4' %} + {% if os9_vlt.backup_destination_vrf is defined and os9_vlt.backup_destination_vrf %} + back-up destination {{ os9_vlt.backup_destination }} vrf {{ os9_vlt.backup_destination_vrf }} + {% else %} + back-up destination {{ os9_vlt.backup_destination }} + {% endif %} + {% endif %} + {% endif %} + {% else %} + no back-up destination + {% endif %} + {% endif %} + {% if os9_vlt.VLTi is defined %} + {% if os9_vlt.VLTi %} + peer-link port-channel {{ os9_vlt.VLTi }} + {% else %} + no peer-link + {% endif %} + {% endif %} + {% if os9_vlt.priority is defined %} + {% if os9_vlt.priority %} + primary-priority {{ os9_vlt.priority }} + {% else %} + no primary-priority + {% endif %} + {% endif %} + {% if os9_vlt.unit_id is defined %} + {% if os9_vlt.unit_id >= 0 %} + unit-id {{ os9_vlt.unit_id }} + {% else %} + no unit-id + {% endif %} + {% endif %} + {% if os9_vlt.peer_routing is defined %} + {% if os9_vlt.peer_routing == True %} + peer-routing + {% else %} + no peer-routing + {% endif %} + {% endif %} + {% if os9_vlt.peer_routing_timeout is defined %} + {% if os9_vlt.peer_routing_timeout %} + peer-routing-timeout {{ os9_vlt.peer_routing_timeout }} + {% else %} + no peer-routing-timeout + {% endif %} + {% endif %} + {% if os9_vlt.multicast_peer_routing_timeout is defined %} + {% if os9_vlt.multicast_peer_routing_timeout %} + multicast peer-routing timeout {{ os9_vlt.multicast_peer_routing_timeout }} + {% else %} + no multicast peer-routing timeout + {% endif %} + {% endif %} + {% if os9_vlt.system_mac is defined and os9_vlt.system_mac %} + system-mac mac-address {{ os9_vlt.system_mac }} + {% else %} + no system-mac + {% endif %} + {% if os9_vlt.delay_restore is defined %} + {% if os9_vlt.delay_restore %} + delay-restore {{ os9_vlt.delay_restore }} + {% else %} + no delay-restore + {% endif %} + {% endif %} + {% if os9_vlt.delay_restore_abort_threshold is defined %} + {% if os9_vlt.delay_restore_abort_threshold %} + delay-restore abort-threshold {{ os9_vlt.delay_restore_abort_threshold }} + {% else %} + no delay-restore abort-threshold + {% endif %} + {% endif %} + + {% if os9_vlt.proxy_gateway is defined and os9_vlt.proxy_gateway %} + {% for key in os9_vlt.proxy_gateway.keys() %} + {% if key == "static" %} + {% set static_vars = os9_vlt.proxy_gateway[key] %} + {% if static_vars.proxy_static_state is defined and static_vars.proxy_static_state =="absent" %} + no proxy-gateway static + {% else %} + proxy-gateway static + {% if static_vars.remote_mac is defined and static_vars.remote_mac %} + {% for mac in static_vars.remote_mac %} + {% if mac.state is defined and mac.state =="absent" %} + {% if mac.address is defined and mac.address %} + {% if mac.exclude_vlan_range is defined and mac.exclude_vlan_range %} + no remote-mac-address {{ mac.address }} exclude-vlan {{ mac.exclude_vlan_range }} + {% else %} + no remote-mac-address {{ mac.address }} + {% endif %} + {% endif %} + {% else %} + {% if mac.address is defined and mac.address %} + {% if mac.exclude_vlan_range is defined and mac.exclude_vlan_range %} + remote-mac-address {{ mac.address }} exclude-vlan {{ mac.exclude_vlan_range }} + {% else %} + remote-mac-address {{ mac.address }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% elif key == "lldp" %} + {% set lldp_vars = os9_vlt.proxy_gateway[key] %} + {% if lldp_vars.proxy_lldp_state is defined and lldp_vars.proxy_lldp_state =="absent" %} + no proxy-gateway lldp + {% else %} + proxy-gateway lldp + {% if lldp_vars.peer_domain_link is defined and lldp_vars.peer_domain_link %} + {% for mac in lldp_vars.peer_domain_link %} + {% if mac.state is defined and mac.state =="absent" %} + {% if mac.port_channel_id is defined and mac.port_channel_id %} + {% if mac.exclude_vlan_range is defined and mac.exclude_vlan_range %} + no peer-domain-link port-channel {{ mac.port_channel_id }} exclude-vlan {{ mac.exclude_vlan_range }} + {% else %} + no peer-domain-link port-channel {{ mac.port_channel_id }} + {% endif %} + {% endif %} + {% else %} + {% if mac.port_channel_id is defined and mac.port_channel_id %} + {% if mac.exclude_vlan_range is defined and mac.exclude_vlan_range %} + peer-domain-link port-channel {{ mac.port_channel_id }} exclude-vlan {{ mac.exclude_vlan_range }} + {% else %} + peer-domain-link port-channel {{ mac.port_channel_id }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% if lldp_vars.vlt_peer_mac is defined %} + {% if lldp_vars.vlt_peer_mac %} + vlt-peer-mac transmit + {% else %} + no vlt-peer-mac transmit + {% endif %} + {% endif %} + {% if lldp_vars.peer_timeout is defined %} + {% if lldp_vars.peer_timeout %} + peer-timeout {{ lldp_vars.peer_timeout }} + {% else %} + no peer-timeout 2 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_vlt/tests/inventory.yaml b/roles/os9_vlt/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_vlt/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_vlt/tests/main.os9.yaml b/roles/os9_vlt/tests/main.os9.yaml new file mode 100644 index 0000000..999d3b5 --- /dev/null +++ b/roles/os9_vlt/tests/main.os9.yaml @@ -0,0 +1,39 @@ +--- +# vars file for dellemc.os9.os9_vlt, +# below gives a example configuration +# Sample variables for OS9 device +os9_vlt: + domain: 3 + backup_destination: 1.1.1.1 + destination_type: ipv4 + backup_destination_vrf: test + priority: 1 + VLTi: 100 + peer_routing: True + peer_routing_timeout: 200 + multicast_peer_routing_timeout: 250 + system_mac: aa:aa:aa:aa:aa:aa + delay_restore: 100 + delay_restore_abort_threshold: 110 + proxy_gateway: + static: + remote_mac: + - address: aa:aa:aa:aa:aa:aa + exclude_vlan_range: 2 + state: present + proxy_static_state: present + lldp: + vlt_peer_mac: true + peer_timeout: 20 + peer_domain_link: + - port_channel_id: 10 + exclude_vlan_range: 3 + state: present + proxy_lldp_state: present + vlt_peers: + Po 12: + peer_lag: 13 + Po 10: + peer_lag: 14 + unit_id: 1 + state: present \ No newline at end of file diff --git a/roles/os9_vlt/tests/test.yaml b/roles/os9_vlt/tests/test.yaml new file mode 100644 index 0000000..c5a1dcf --- /dev/null +++ b/roles/os9_vlt/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_vlt \ No newline at end of file diff --git a/roles/os9_vlt/vars/main.yml b/roles/os9_vlt/vars/main.yml new file mode 100644 index 0000000..1153167 --- /dev/null +++ b/roles/os9_vlt/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_vlt \ No newline at end of file diff --git a/roles/os9_vrf/LICENSE b/roles/os9_vrf/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_vrf/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_vrf/README.md b/roles/os9_vrf/README.md new file mode 100644 index 0000000..1061256 --- /dev/null +++ b/roles/os9_vrf/README.md @@ -0,0 +1,125 @@ +VRF role +======== + +This role facilitates to configure the basics of virtual routing and forwarding (VRF) that helps in the partition of physical routers to multiple virtual routers. This role is abstracted Dell EMC platforms running OS9. + +The vrf role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- Role is abstracted using the variable *ansible_network_os* that can take the dellemc.os9.os9 as a value. +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration. +- Variables and values are case-sensitive + +**os9_vrf keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``vrfdetails`` | list | Configures the list of VRF instances (see ``instances.*``) | os9 | +| ``vrfdetails.vrf_name`` | string | Specifies the VRF instance name (default is management) | os9 | +| ``vrfdetails.vrf_id`` | integer (required) | Configures the VRF ID for the corresponding vrf | os9 | +| ``vrfdetails.description`` | string | Configures a one line description for the VRF | os9 | +| ``vrfdetails.state`` | string | Deletes the VRF instance name if set to absent | os9 | +| ``vrfdetails.tagged_portname`` | list | Specifies list of valid interface names | os9 | +| ``tagged_portname.port`` | string | Specifies valid interface name | os9 | +| ``tagged_portname.state`` | string | Deletes VRF association in the interface if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_vrf* role is built on modules included in the core Ansible code. These modules were added in ansible version 2.2.0 + +Example playbook +---------------- + +This example uses the *os9_vrf* role to setup a VRF and associate it to an interface. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that references the *os9_vrf* role. + +*upd_src_ip_loopback_id* has an dependency with association of the interface in a VRF. So the *os9_vrf* role needs to be invoked twice with different input dictionary one for the create and one for *upd_src_ip_loopback_id*, refer the example playbook for more details. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1 for os9 device + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_vrf: + vrfdetails: + - vrf_name: "os9vrf" + state: "present" + ip_route_import: + community_value: "10:20" + state: "present" + ip_route_export: + community_value: "30:40" + state: "present" + ipv6_route_import: + community_value: "40:50" + state: "absent" + ipv6_route_export: + community_value: "60:70" + state: "absent" + map_ip_interface: + - intf_id : "loopback11" + state : "present" + + os9_vrf_upd_src_loopback: + vrfdetails: + - vrf_name: "os9vrf" + state: "present" + upd_src_ip_loopback_id: 11 + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_vrf + +**Simple playbook to setup os9 with upd_src_ip_loopback_id - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_vrf + - hosts: leaf1 + vars: + os9_vrf: "{{ os9_vrf_upd_src_loopback }}" + roles: + - dellemc.os9.os9_vrf + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_vrf/defaults/main.yml b/roles/os9_vrf/defaults/main.yml new file mode 100644 index 0000000..5f46d64 --- /dev/null +++ b/roles/os9_vrf/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_vrf \ No newline at end of file diff --git a/roles/os9_vrf/handlers/main.yml b/roles/os9_vrf/handlers/main.yml new file mode 100644 index 0000000..accc50f --- /dev/null +++ b/roles/os9_vrf/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_vrf \ No newline at end of file diff --git a/roles/os9_vrf/meta/main.yml b/roles/os9_vrf/meta/main.yml new file mode 100644 index 0000000..0411392 --- /dev/null +++ b/roles/os9_vrf/meta/main.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2020 Dell Inc. or its subsidiaries. All Rights Reserved. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_vrf role facilitates the configuration of VRF attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - emc + - dellemc + - os9 \ No newline at end of file diff --git a/roles/os9_vrf/tasks/main.yml b/roles/os9_vrf/tasks/main.yml new file mode 100644 index 0000000..7b52618 --- /dev/null +++ b/roles/os9_vrf/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating VRF configuration for os9" + template: + src: os9_vrf.j2 + dest: "{{ build_dir }}/vrf9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False'))| bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning VRF configuration for os9" + os9_config: + src: os9_vrf.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_vrf/templates/os9_vrf.j2 b/roles/os9_vrf/templates/os9_vrf.j2 new file mode 100644 index 0000000..2069013 --- /dev/null +++ b/roles/os9_vrf/templates/os9_vrf.j2 @@ -0,0 +1,68 @@ +#jinja2: trim_blocks: True,lstrip_blocks: True +{################################ +Purpose: +Configure VRF on os9 Devices. +os9_vrf: + vrfdetails: + - vrf_id: 1 + vrf_name: VLTi-KEEPALIVE + description: VRF-to-support-Peer-Keepalive-Link + state: present + tagged_portname: + - port: fortyGige 1/2 + state: present + - port: fortyGige 1/3 + state: absent +################################} +{% if (os9_vrf is defined and os9_vrf) %} +{% if os9_vrf.vrfdetails is defined %} + {% for vrf in os9_vrf.vrfdetails %} + {% if vrf.vrf_name is defined %} + {% if vrf.vrf_name %} + {% if vrf.state is defined and vrf.state == 'absent' %} + {% if vrf.tagged_portname is defined and vrf.tagged_portname %} + {% for tag in vrf.tagged_portname %} + {% if tag.state is defined and tag.state == 'absent' %} + {% if tag.port is defined and tag.port %} +interface {{ tag.port }} + no ip vrf forwarding + exit + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +no ip vrf {{ vrf.vrf_name }} + {% else %} + {% if vrf.vrf_id is defined %} + {% if vrf.vrf_id %} +feature vrf +ip vrf {{ vrf.vrf_name }} {{ vrf.vrf_id }} + {% if vrf.description is defined %} + {% if vrf.description %} + description {{ vrf.description }} + {% else %} + no description sample + {% endif %} + {% endif %} + {% if vrf.tagged_portname is defined %} + {% if vrf.tagged_portname %} + {% for tag in vrf.tagged_portname %} + {% if tag.port is defined and tag.port %} +interface {{ tag.port }} + {% if tag.state is defined and tag.state == 'absent' %} + no ip vrf forwarding + {% else %} + ip vrf forwarding {{ vrf.vrf_name }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_vrf/tests/inventory.yaml b/roles/os9_vrf/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_vrf/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_vrf/tests/main.os9.yaml b/roles/os9_vrf/tests/main.os9.yaml new file mode 100644 index 0000000..865dcc3 --- /dev/null +++ b/roles/os9_vrf/tests/main.os9.yaml @@ -0,0 +1,15 @@ +--- +# vars file for dellemc.os9.os9_vrf, +# below gives a sample configuration +# Sample variables for OS9 device +os9_vrf: + vrfdetails: + - vrf_id: 23 + vrf_name: VRFi-KEEPALIVE + description: test + state: absent + tagged_portname: + - port: fortyGigE 1/7 + state: absent + - port: fortyGigE 1/8 + state: absent \ No newline at end of file diff --git a/roles/os9_vrf/tests/test.yaml b/roles/os9_vrf/tests/test.yaml new file mode 100644 index 0000000..286efc5 --- /dev/null +++ b/roles/os9_vrf/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_vrf \ No newline at end of file diff --git a/roles/os9_vrf/vars/main.yml b/roles/os9_vrf/vars/main.yml new file mode 100644 index 0000000..0d4921a --- /dev/null +++ b/roles/os9_vrf/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_vrf \ No newline at end of file diff --git a/roles/os9_vrrp/LICENSE b/roles/os9_vrrp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_vrrp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_vrrp/README.md b/roles/os9_vrrp/README.md new file mode 100644 index 0000000..4b00829 --- /dev/null +++ b/roles/os9_vrrp/README.md @@ -0,0 +1,153 @@ +VRRP role +========= + +This role facilitates configuring virtual router redundancy protocol (VRRP) attributes. It supports the creation of VRRP groups for interfaces and setting the VRRP group attributes. This role is abstracted for Dell EMC platforms running os9. + +The VRRP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in Dell EMC Networking OS connection variables. + +Role variables +-------------- + +- Role is abstracted using the *ansible_network_os* variable that can take the dellemc.os9.os9 as a value +- If *os9_cfg_generate* is set to true, the variable generates the role configuration commands in a file +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value for any variable negates the corresponding configuration +- *os9_vrrp* (dictionary) holds a dictionary with the interface name key +- Interface name can correspond to any of the valid os9 interface with a unique interface identifier name +- Physical interfaces names must be in * * format (for example *fortyGigE 1/1*) +- Logical interface names must be in * * format (for example, *vlan 1* for os9) +- Variables and values are case-sensitive + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|-----------------------| +| ``vrrp`` | dictionary | Configures VRRP commands (see ``vrrp.*``) | os9 | +| ``delay_min`` | integer | Configures the minimum delay timer applied after interface up event (0 to 900 | os9 | +| ``delay_reload`` | integer | Configures the minimum delay timer applied after boot (0 to 900) | os9 | +| ``vrrp_group`` | list | Configures VRRP group commands (see ``vrrp_group.*``) | os9 | +| ``vrrp_group.type`` | string: ipv6,ipv4 | Specifies the type of the VRRP group | os9 | +| ``vrrp_group.group_id`` | integer (required) | Configures the ID for the VRRP group (1 to 255) | os9 | +| ``vrrp_group.description`` | string | Configures a single line description for the VRRP group | os9 | +| ``vrrp_group.virtual_address`` | string | Configures a virtual-address to the VRRP group (A.B.C.D format) | os9 | +| ``vrrp_group.enable`` | boolean: true,false | Enables/disables the VRRP group at the interface | os9 | +| ``vrrp_group.preempt`` | boolean: true\*,false | Configures preempt mode on the VRRP group | os9 | +| ``vrrp_group.priority`` |integer | Configures priority for the VRRP group (1 to 255; default 100) | os9 | +| ``vrrp_group.version`` | string: 2\*,3,both | Configures the VRRP version of the VRRP group; not supported when *vrrp_group.type* is "ipv6" | os9 | +| ``vrrp_group.hold_time_centisecs`` | integer | Configures the hold-time for the VRRP group in centiseconds (0 to 65525 and in multiple of 25; default 100); centisecs gets converted into seconds in version 2 | os9 | +| ``vrrp_group.adv_interval_centisecs`` | integer | Configures the advertisement interval for the VRRP group in centiseconds (25 to 4075; default 100) and in multiple of 25; centisecs gets converted into seconds in version 2 | os9 | +| ``vrrp_group.track_interface`` | list | Configures the track interface of the VRRP group (see ``track.*``) | os9 | +| ``track_interface.resource_id`` | integer | Configures the object tracking resource ID of the VRRP group; mutually exclusive with *track.interface* | os9 | +| ``track_interface.interface`` | string | Configures the track interface of the VRRP group ( format) | os9 | +| ``track_interface.priority_cost`` | integer | Configures the priority cost for track interface of the VRRP group (1 to 254; default 10) | os9 | +| ``track_interface.state`` | string: present\*,absent | Deletes the specific track interface from the VRRP group if set to absent | os9 | +| ``vrrp_group.track_interface_state`` | string: present*,absent | Deletes all track interfaces from the VRRP group if set to absent | os9 | +| ``vrrp_group.authentication`` | dictionary | Configures the authentication type for the VRRP group (see ``authentication.*``); not supported when ``vrrp_group.type`` is "ipv6" | os9 | +| ``authentication.key`` | string (required): 0,7,LINE | Configures the authentication key for the VRRP group | os9 | +| ``authentication.key_string`` | string | Configures the user key string; if key is 7, this variable takes the hidden user key string; if key is 0, this variable takes the unencrypted user key (clear-text); supported only if the value of *authentication.key* is 7 or 0 | os9 | +| ``authentication.state`` | string: present\*,absent | Deletes authentication from the interface VRRP group if set to absent | os9 | +| ``vrrp_group.state`` | string: present\*,absent | Deletes the VRRP group from the interface if set to absent | os9 | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories, or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-----------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_vrrp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_vrrp* role to configure VRRP commands at the interfaces. It creates a *hosts* file with the switch details and corresponding variables. The hosts file should define the *ansible_network_os* variable with corresponding Dell EMC networking OS name. + +When *os9_cfg_generate* is set to true, the variable generates the configuration commands as a .part file in *build_dir* path. By default, the variable is set to false. It writes a simple playbook that only references the *os9_vrrp* role. + +**Sample hosts file** + + leaf1 ansible_host= + +**Sample host_vars/leaf1** + + hostname: leaf1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + os9_vrrp: + fortyGigE 1/5: + vrrp: + delay_min: 2 + delay_reload: 3 + vrrp_group: + - group_id: 2 + type: ipv6 + description: "Interface-vrrp-ipv6" + virtual_address: 2001:4898:5808:ffa3::9 + enable: true + priority: 120 + preempt: false + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortyGigE 1/11 + state: present + track_interface_state: present + adv_interval_centisecs: 200 + hold_time_centisecs: 20 + - group_id: 4 + state: present + description: "Interface-vrrp4" + virtual_address: 10.28.0.2 + enable: true + priority: 120 + preempt: false + version: both + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortGigE 1/10 + state: present + track_interface_state: present + adv_interval_centisecs: 225 + hold_time_centisecs: 25 + authentication: + key: 0 + key_string: vrrpkey + state: present + +**Simple playbook to setup system - leaf.yaml** + + - hosts: leaf1 + roles: + - dellemc.os9.os9_vrrp + +**Run** + + ansible-playbook -i hosts leaf.yaml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_vrrp/defaults/main.yml b/roles/os9_vrrp/defaults/main.yml new file mode 100644 index 0000000..2d4f531 --- /dev/null +++ b/roles/os9_vrrp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_vrrp \ No newline at end of file diff --git a/roles/os9_vrrp/handlers/main.yml b/roles/os9_vrrp/handlers/main.yml new file mode 100644 index 0000000..7876000 --- /dev/null +++ b/roles/os9_vrrp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_vrrp \ No newline at end of file diff --git a/roles/os9_vrrp/meta/main.yml b/roles/os9_vrrp/meta/main.yml new file mode 100644 index 0000000..76ceadf --- /dev/null +++ b/roles/os9_vrrp/meta/main.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: > + The os9_vrrp role facilitates the configuration of Virtual Router Redundancy Protocol (VRRP) attributes in + devices running Dell EMC Networking Operating Systems. + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + galaxy_tags: + - networking + - dell + - dellemc + - emc + - os9 \ No newline at end of file diff --git a/roles/os9_vrrp/tasks/main.yml b/roles/os9_vrrp/tasks/main.yml new file mode 100644 index 0000000..63034ef --- /dev/null +++ b/roles/os9_vrrp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating VRRP configuration for os9" + template: + src: os9_vrrp.j2 + dest: "{{ build_dir }}/vrrp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning VRRP configuration for os9" + os9_config: + src: os9_vrrp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_vrrp/templates/os9_vrrp.j2 b/roles/os9_vrrp/templates/os9_vrrp.j2 new file mode 100644 index 0000000..f3e4a1d --- /dev/null +++ b/roles/os9_vrrp/templates/os9_vrrp.j2 @@ -0,0 +1,218 @@ +#jinja2: trim_blocks: True, lstrip_blocks: True +{########################################## +Purpose: +Configure VRRP commands for os9 Devices +os9_vrrp: + fortyGigE 1/4: + vrrp: + delay_min: 2 + delay_reload: 2 + vrrp_group: + - group_id: 2 + type: ipv6 + description: "Interface-vrrp-ipv6" + virtual_address: 2001:4898:5808:ffa3::9 + enable: true + priority: 120 + preempt: false + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortyGigE 1/10 + state: present + track_interface_state: present + adv_interval_centisecs: 200 + hold_time_centisecs: 20 + state: present + + - group_id: 4 + state: present + description: "Interface-vrrp4" + virtual_address: 10.2.0.1 + enable: true + priority: 120 + preempt: false + version: 2 + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortyGigE 1/12 + state: present + track_interface_state: present + adv_interval_centisecs: 200 + hold_time_centisecs: 20 + authentication: + key: 0 + key_string: vrrpkey + state: present +#########################################} +{% if os9_vrrp is defined and os9_vrrp %} +{% for key,value in os9_vrrp.items() %} +interface {{ key }} + {% if value %} + {% if value.vrrp is defined and value.vrrp %} + {% if value.vrrp.delay_min is defined %} + {% if value.vrrp.delay_min >=0 %} + vrrp delay minimum {{ value.vrrp.delay_min }} + {% else %} + no vrrp delay minimum + {% endif %} + {% endif %} + {% if value.vrrp.delay_reload is defined %} + {% if value.vrrp.delay_reload >=0 %} + vrrp delay reload {{ value.vrrp.delay_reload }} + {% else %} + vrrp delay reload {{ value.vrrp.delay_reload }} + {% endif %} + {% endif %} + {% endif %} + {% for group in value.vrrp_group %} + {% if group.group_id is defined and group.group_id %} + {% if group.state is defined and group.state == "absent" %} + {% if group.type is defined and group.type == "ipv6" %} + no vrrp-ipv6-group {{ group.group_id }} + {% else %} + no vrrp-group {{ group.group_id }} + {% endif %} + {% else %} + {% if group.type is defined and group.type == "ipv6" %} + vrrp-ipv6-group {{ group.group_id }} + {% else %} + vrrp-group {{ group.group_id }} + {% endif %} + {% if group.type is not defined or not group.type == "ipv6" %} + {% if group.version is defined %} + {% if group.version %} + version {{ group.version }} + {% else %} + no version + {% endif %} + {% endif %} + {% endif %} + {% if group.adv_interval_centisecs is defined %} + {% if group.adv_interval_centisecs %} + {% if group.version is not defined or (group.version is defined and group.version == 2) %} + {% set adv_int = group.adv_interval_centisecs/100 %} + {% if group.type is defined and group.type == "ipv6" %} + advertise-interval centisecs {{ group.adv_interval_centisecs }} + {% else %} + advertise-interval {{ adv_int|int }} + {% endif %} + {% else %} + advertise-interval centisecs {{ group.adv_interval_centisecs }} + {% endif %} + {% else %} + no advertise-interval + {% endif %} + {% endif %} + {% if group.hold_time_centisecs is defined %} + {% if group.hold_time_centisecs >= 0 %} + {% if group.version is not defined or (group.version is defined and group.version == 2) %} + {% set hold_time = group.hold_time_centisecs/100 %} + {% if group.type is defined and group.type == "ipv6" %} + hold-time centisecs {{ group.hold_time_centisecs }} + {% else %} + hold-time {{ hold_time|int }} + {% endif %} + {% else %} + hold-time centisecs {{ group.hold_time_centisecs }} + {% endif %} + {% else %} + no hold-time + {% endif %} + {% endif %} + {% if group.track_interface_state is defined and group.track_interface_state == "absent" %} + no track + {% else %} + {% if group.track_interface is defined and group.track_interface %} + {% for track_item in group.track_interface %} + {% if track_item.state is defined and track_item.state == "absent" %} + {% if track_item.resource_id is defined and track_item.resource_id %} + no track {{ track_item.resource_id }} + {% elif track_item.interface is defined and track_item.interface %} + no track {{ track_item.interface }} + {% endif %} + {% else %} + {% if track_item.resource_id is defined and track_item.resource_id %} + {% if track_item.priority_cost is defined and track_item.priority_cost %} + track {{ track_item.resource_id }} priority-cost {{ track_item.priority_cost }} + {% else %} + track {{ track_item.resource_id }} + {% endif %} + {% elif track_item.interface is defined and track_item.interface %} + {% if track_item.priority_cost is defined and track_item.priority_cost %} + track {{ track_item.interface }} priority-cost {{ track_item.priority_cost }} + {% else %} + track {{ track_item.interface }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% if group.type is not defined or not group.type == "ipv6" %} + {% if group.authentication is defined and group.authentication %} + {% if group.authentication.state is defined and group.authentication.state == "absent" %} + no authentication-type + {% else %} + {% if group.authentication.key is defined %} + {% if group.version is not defined or (group.version is defined and group.version == 2) %} + {% if group.authentication.key == 0 or group.authentication.key == 7 %} + {% if group.authentication.key_string is defined and group.authentication.key_string %} + authentication-type simple {{ group.authentication.key }} {{ group.authentication.key_string }} + {% endif %} + {% elif group.authentication.key %} + authentication-type simple {{ group.authentication.key }} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if group.virtual_address is defined %} + {% if group.virtual_address %} + virtual-address {{ group.virtual_address }} + {% else %} + no virtual-address + {% endif %} + {% endif %} + {% if group.description is defined %} + {% if group.description %} + description {{ group.description }} + {% else %} + no description + {% endif %} + {% endif %} + {% if group.preempt is defined %} + {% if group.preempt %} + preempt + {% else %} + no preempt + {% endif %} + {% endif %} + {% if group.enable is defined %} + {% if group.enable %} + no disable + {% else %} + disable + {% endif %} + {% endif %} + {% if group.priority is defined %} + {% if group.priority %} + priority {{ group.priority }} + {% else %} + no priority + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_vrrp/tests/inventory.yaml b/roles/os9_vrrp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_vrrp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_vrrp/tests/main.os9.yaml b/roles/os9_vrrp/tests/main.os9.yaml new file mode 100644 index 0000000..856d381 --- /dev/null +++ b/roles/os9_vrrp/tests/main.os9.yaml @@ -0,0 +1,59 @@ +--- +# vars file for dellemc.os9.os9_vrrp, +# below gives a example configuration +# Sample variables for OS9 device +os9_vrrp: + fortyGigE 0/28: + vrrp: + delay_min: 4 + delay_reload: 5 + vrrp_group: + - group_id: 2 + type: ipv6 + description: "Interface-vrrp-ipv6" + virtual_address: 2001:4898:5808:ffa3::9 + enable: true + priority: 120 + preempt: false + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortyGigE 0/40 + state: present + track_interface_state: present + adv_interval_centisecs: 200 + hold_time_centisecs: 20 + state: present + - group_id: 4 + state: present + description: "Interface-vrrp4" + virtual_address: 10.28.0.2 + enable: true + priority: 120 + preempt: false + version: 3 + track_interface: + - resource_id: 3 + priority_cost: 25 + state: present + - interface: port-channel 120 + priority_cost: 20 + - interface: fortyGigE 0/20 + state: absent + track_interface_state: present + adv_interval_centisecs: 200 + hold_time_centisecs: 200 + authentication: + key: 0 + key_string: vrrpkey + state: present + - group_id: 3 + state: present + description: "Interface-vrrp3" + virtual_address: 10.28.0.3 + enable: true + priority: 120 + preempt: false \ No newline at end of file diff --git a/roles/os9_vrrp/tests/test.yaml b/roles/os9_vrrp/tests/test.yaml new file mode 100644 index 0000000..a12c274 --- /dev/null +++ b/roles/os9_vrrp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_vrrp \ No newline at end of file diff --git a/roles/os9_vrrp/vars/main.yml b/roles/os9_vrrp/vars/main.yml new file mode 100644 index 0000000..c241486 --- /dev/null +++ b/roles/os9_vrrp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_vrrp \ No newline at end of file diff --git a/roles/os9_xstp/LICENSE b/roles/os9_xstp/LICENSE new file mode 100644 index 0000000..e2775b4 --- /dev/null +++ b/roles/os9_xstp/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2020, Dell EMC. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/roles/os9_xstp/README.md b/roles/os9_xstp/README.md new file mode 100644 index 0000000..3f1830b --- /dev/null +++ b/roles/os9_xstp/README.md @@ -0,0 +1,130 @@ +# xSTP role + +This role facilitates the configuration of xSTP attributes. It supports multiple version of spanning-tree protocol (STP), rapid spanning-tree (RSTP), rapid per-VLAN spanning-tree (Rapid PVST+), multiple spanning-tree (MST), and per-VLAN spanning-tree (PVST). It supports the configuration of bridge priority, enabling and disabling spanning-tree, creating and deleting instances, and mapping virtual LAN (VLAN) to instances. This role is abstracted for Dell EMC platforms running OS9. + +The xSTP role requires an SSH connection for connectivity to a Dell EMC Networking device. You can use any of the built-in OS connection variables . + +Role variables +-------------- + +- *os9_xstp*(dictionary) contains the hostname (dictionary) +- Hostname is the value of the *hostname* variable that corresponds to the name of the OS device +- Role is abstracted using the *ansible_network_os* variable that can take dellemc.os9.os9 as a value. +- Any role variable with a corresponding state variable set to absent negates the configuration of that variable +- Setting an empty value to any variable negates the corresponding configuration +- Variables and values are case-sensitive + +**hostname keys** + +| Key | Type | Description | Support | +|------------|---------------------------|---------------------------------------------------------|----------------------| +| ``type`` | string (required) | Configures the type of spanning-tree mode specified that can vary according to the OS device; os9 devices include STP, RSTP, PVST, MSTP; | os9 | +| ``enable`` | boolean: true,false | Enables/disables the spanning-tree protocol specified in the type variable | os9 | +| ``stp`` | dictionary | Configures simple spanning-tree protocol (see ``stp.* keys``) | os9 | +| ``stp.bridge_priority`` | integer | Configures bridge-priority for the spanning-tree (0 to 61440 range in multiples of 4096) | os9 | +| ``stp.state`` | string: absent,present\* | Deletes the configured STP if set to absent | os9 | +| ``rstp`` | dictionary | Configures rapid spanning-tree (see ``rstp.*``) | os9 | +| ``rstp.bridge_priority`` | integer | Configures bridge-priority for the spanning-tree (0 to 61440 range in multiples of 4096) | os9 | +| ``rstp.state ``| string: absent,present\* | Deletes the configured RSTP in os9 devices if set to absent | os9 | +| ``pvst`` | dictionary | Configures per-VLAN spanning-tree protocol (see ``pvst.*``) | os9 | +| ``pvst.vlan`` | list | Configures the VLAN for PVST (see ``vlan.*``) | os9 | +| ``vlan.range_or_id`` | string | Configures a VLAN/range of VLANs for the per-VLAN spanning-tree protocol | os9 | +| ``vlan.bridge_priority`` | integer | Configures bridge-priority for the per-VLAN spanning-tree (0 to 61440 range in multiples of 4096); mutually exclusive with *vlan.root* | os9 | +| ``pvst.state`` | string: absent,present\* | Deletes the configured PVST if set to absent | os9 | +| ``mstp`` | dictionary | Configures multiple spanning-tree protocol (see ``mstp.*``) | os9 | +| ``mstp.mstp_instances`` | list | Configures a MSTP instance (see ``mstp_instances.*``) | os9 | +| ``mstp_instances.number`` | integer | Configures the multiple spanning-tree instance number | os9 | +| ``mstp_instances.vlans`` | string | Configures a VLAN/range of VLANs by mapping it to the instance number in os9 devices | os9 | +| ``mstp_instances.bridge_priority`` | integer | Configures the bridge-priority for the spanning-tree (0 to 61440 range in multiples of 4096); mutually exclusive with *mstp_instances.root* | os9 | +| ``mstp_instances.vlans_state`` | string: absent,present\* | Deletes a set of VLANs mapped to the spanning-tree instance if set to absent | os9 | +| ``mstp.state`` | string: absent,present\* | Deletes the configured MSTP if set to absent | os9 | +| ``intf`` | list | Configures multiple spanning-tree in an interface (see ``intf.*``) | os9 | +| ``intf ``| dictionary | Configures the interface name (see ``intf..*``) | os9 | +| ``intf..stp_type`` | list: stp,mstp,MSTi,pvst,rstp | Configures the list of spanning-tree in an interface | os9 | +| ``intf..edge_port`` | boolean: true,false | in os9 devices according to the stp_type EdgePort is configured; | os9 | + +> **NOTE**: Asterisk (_*_) denotes the default value if none is specified. + +Connection variables +-------------------- + +Ansible Dell EMC Networking roles require connection information to establish communication with the nodes in your inventory. This information can exist in the Ansible *group_vars* or *host_vars* directories or inventory or in the playbook itself. + +| Key | Required | Choices | Description | +|-------------|----------|------------|-------------------------------------------------------| +| ``ansible_host`` | yes | | Specifies the hostname or address for connecting to the remote device over the specified transport | +| ``ansible_port`` | no | | Specifies the port used to build the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_PORT option is used; it defaults to 22 | +| ``ansible_ssh_user`` | no | | Specifies the username that authenticates the CLI login for the connection to the remote device; if value is unspecified, the ANSIBLE_REMOTE_USER environment variable value is used | +| ``ansible_ssh_pass`` | no | | Specifies the password that authenticates the connection to the remote device. | +| ``ansible_become`` | no | yes, no\* | Instructs the module to enter privileged mode on the remote device before sending any commands; if value is unspecified, the ANSIBLE_BECOME environment variable value is used, and the device attempts to execute all commands in non-privileged mode | +| ``ansible_become_method`` | no | enable, sudo\* | Instructs the module to allow the become method to be specified for handling privilege escalation; if value is unspecified, the ANSIBLE_BECOME_METHOD environment variable value is used. | +| ``ansible_become_pass`` | no | | Specifies the password to use if required to enter privileged mode on the remote device; if ``ansible_become`` is set to no this key is not applicable. | +| ``ansible_network_os`` | yes | os9, null\* | This value is used to load the correct terminal and cliconf plugins to communicate with the remote device. | + +> **NOTE**: Asterisk (\*) denotes the default value if none is specified. + +Dependencies +------------ + +The *os9_xstp* role is built on modules included in the core Ansible code. These modules were added in Ansible version 2.2.0. + +Example playbook +---------------- + +This example uses the *os9_xstp* role to configure different variants of spanning-tree. Based on the type of STP and defined objects, VLANs are associated and bridge priorities are assigned. It creates a *hosts* file with the switch details, and a *host_vars* file with connection variables. The corresponding role variables are defined in the *vars/main.yml* file at the role path. +It writes a simple playbook that only references the *os9_xstp* role. By including the role, you automatically get access to all of the tasks to configure xSTP. + +**Sample hosts file** + + spine1 ansible_host= + +**Sample host_vars/spine1** + + hostname: spine1 + ansible_become: yes + ansible_become_method: xxxxx + ansible_become_pass: xxxxx + ansible_ssh_user: xxxxx + ansible_ssh_pass: xxxxx + ansible_network_os: dellemc.os9.os9 + build_dir: ../temp/os9 + + +**Sample vars/main.yml** + + os9_xstp: + type: rstp + enable: true + stp: + bridge_priority: 4096 + state: present + rstp: + bridge_priority: 4096 + pvst: + vlan: + - range_or_id: 10 + bridge_priority: 4096 + mstp: + mstp_instances: + - number: 1 + vlans: 10,12 + bridge_priority: 4096 + vlans_state: present + intf: + fortyGigE 1/25: + stp_type: + - stp + - mstp + edge_port: true + +**Simple playbook to setup system - spine.yml** + + - hosts: spine + roles: + - dellemc.os9.os9_xstp + +**Run** + + ansible-playbook -i hosts spine.yml + +(c) 2020 Dell Inc. or its subsidiaries. All Rights Reserved. diff --git a/roles/os9_xstp/defaults/main.yml b/roles/os9_xstp/defaults/main.yml new file mode 100644 index 0000000..d49cf4a --- /dev/null +++ b/roles/os9_xstp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for dellemc.os9.os9_xstp \ No newline at end of file diff --git a/roles/os9_xstp/handlers/main.yml b/roles/os9_xstp/handlers/main.yml new file mode 100644 index 0000000..818e833 --- /dev/null +++ b/roles/os9_xstp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for dellemc.os9.os9_xstp \ No newline at end of file diff --git a/roles/os9_xstp/meta/main.yml b/roles/os9_xstp/meta/main.yml new file mode 100644 index 0000000..2f41c1c --- /dev/null +++ b/roles/os9_xstp/meta/main.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2020 Dell Inc. +--- +galaxy_info: + author: Dell EMC Networking Engineering + description: The os9_xstp role facilitates the configuration of STP attributes in devices running Dell EMC Networking Operating Systems. + company: Dell Inc + license: Apache 2.0 + min_ansible_version: 2.2 + + platforms: + - name: os9 + + + galaxy_tags: + - networking + - dell + - dellemc + - emc + - os9 \ No newline at end of file diff --git a/roles/os9_xstp/tasks/main.yml b/roles/os9_xstp/tasks/main.yml new file mode 100644 index 0000000..f841959 --- /dev/null +++ b/roles/os9_xstp/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# tasks file for os9 + - name: "Generating xSTP configuration for os9" + template: + src: os9_xstp.j2 + dest: "{{ build_dir }}/xstp9_{{ hostname }}.conf.part" + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") and ((os9_cfg_generate | default('False')) | bool) +# notify: save config os9 + register: generate_output + + - name: "Provisioning xSTP configuration for os9" + os9_config: + src: os9_xstp.j2 + when: (ansible_network_os is defined and ansible_network_os == "dellemc.os9.os9") +# notify: save config os9 + register: output \ No newline at end of file diff --git a/roles/os9_xstp/templates/os9_xstp.j2 b/roles/os9_xstp/templates/os9_xstp.j2 new file mode 100644 index 0000000..b21ee59 --- /dev/null +++ b/roles/os9_xstp/templates/os9_xstp.j2 @@ -0,0 +1,160 @@ +#jinja2: trim_blocks: True, lstrip_blocks: True +{############################################# +PURPOSE: Configure xSTP commands for os9 Devices +os9_xstp: + type: stp + enable: true + stp: + bridge_priority: 4096 + state: present + + rstp: + bridge_priority: 4096 + state: present + + pvst: + vlan: + - range_or_id: 10 + bridge_priority: 4096 + state: present + + mstp: + mstp_instances: + - number: 1 + vlans: 10,12 + vlans_state: present + bridge_priority: 4096 + state: present + intf: + fortyGigE 1/1: + stp_type: + - rstp + - mstp + edge_port: true +############################################} +{% if os9_xstp is defined and os9_xstp %} +{% set xstp_vars = os9_xstp %} +{% if xstp_vars.type is defined and xstp_vars.type %} + {% if xstp_vars.type == "stp" %} +protocol spanning-tree 0 + {% else %} +protocol spanning-tree {{ xstp_vars.type }} + {% endif %} + {% if xstp_vars.enable is defined %} + {% if xstp_vars.enable %} + no disable + {% else %} + disable + {% endif %} + {% endif %} +{% endif %} + +{% if xstp_vars.stp is defined and xstp_vars.stp %} + {% set val = xstp_vars.stp %} + {% if val.state is defined and val.state == "absent" %} +no protocol spanning-tree 0 + {% else %} + {% if val.bridge_priority is defined %} +protocol spanning-tree 0 + {% if val.bridge_priority == 0 or val.bridge_priority %} + bridge-priority {{ val.bridge_priority }} + {% else %} + no bridge-priority + {% endif %} + {% endif %} + {% endif %} +{% endif %} + +{% if xstp_vars.rstp is defined and xstp_vars.rstp %} + {% set val = xstp_vars.rstp %} + {% if val.state is defined and val.state == "absent" %} +no protocol spanning-tree rstp + {% else %} + {% if val.bridge_priority is defined %} +protocol spanning-tree rstp + {% if val.bridge_priority == 0 or val.bridge_priority %} + bridge-priority {{ val.bridge_priority }} + {% else %} + no bridge-priority + {% endif %} + {% endif %} + {% endif %} +{% endif %} + +{% if xstp_vars.pvst is defined and xstp_vars.pvst %} + {% set val = xstp_vars.pvst %} + {% if val.state is defined and val.state == "absent" %} +no protocol spanning-tree pvst + {% else %} + {% if val.vlan is defined and val.vlan %} +protocol spanning-tree pvst + {% for vlan in val.vlan %} + {% if vlan.range_or_id is defined and vlan.range_or_id %} + {% if vlan.bridge_priority is defined %} + {% if vlan.bridge_priority == 0 or vlan.bridge_priority %} + vlan {{ vlan.range_or_id }} bridge-priority {{ vlan.bridge_priority }} + {% else %} + no vlan {{ vlan.range_or_id }} bridge-priority + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} +{% endif %} + +{% if xstp_vars.mstp is defined and xstp_vars.mstp %} + {% set val = xstp_vars.mstp %} + {% if val.state is defined and val.state == "absent" %} +no protocol spanning-tree mstp + {% else %} + {% if val.mstp_instances is defined and val.mstp_instances %} +protocol spanning-tree mstp + {% for instance in val.mstp_instances %} + {% if instance.number is defined and instance.number %} + {% if instance.bridge_priority is defined %} + {% if instance.bridge_priority == 0 or instance.bridge_priority %} + MSTI {{ instance.number }} bridge-priority {{ instance.bridge_priority }} + {% else %} + no MSTI {{ instance.number }} bridge-priority + {% endif %} + {% endif %} + {% if instance.vlans is defined and instance.vlans %} + {% if instance.vlans_state is defined and instance.vlans_state == "absent" %} + no MSTI {{ instance.number }} VLAN {{ instance.vlans }} + {% else %} + MSTI {{ instance.number }} VLAN {{ instance.vlans }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} +{% endif %} + +{% if xstp_vars.intf is defined and xstp_vars.intf %} + {% for intr in xstp_vars.intf.keys() %} + {% set intf_vars = xstp_vars.intf[intr] %} +interface {{ intr }} + {% for type in intf_vars.stp_type %} + {% if type == "stp" %} + {% if intf_vars.edge_port is defined %} + {% if not intf_vars.edge_port %} + no spanning-tree 0 portfast + {% else %} + spanning-tree 0 portfast bpduguard + {% endif %} + {% endif %} + {% else %} + {% if intf_vars.edge_port is defined %} + {% if intf_vars.edge_port %} + spanning-tree {{ type }} edge-port + {% else %} + no spanning-tree {{ type }} edge-port + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + {% endfor %} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/roles/os9_xstp/tests/inventory.yaml b/roles/os9_xstp/tests/inventory.yaml new file mode 100644 index 0000000..5fd33c9 --- /dev/null +++ b/roles/os9_xstp/tests/inventory.yaml @@ -0,0 +1,20 @@ +spine1 ansible_host=100.94.210.44 +spine2 ansible_host=10.11.182.26 +leaf1 ansible_host=10.11.182.27 +leaf2 ansible_host=10.11.182.28 +leaf3 ansible_host=10.11.182.29 +leaf4 ansible_host=10.11.182.30 + +[spine] +spine1 +spine2 + +[leaf] +leaf1 +leaf2 +leaf3 +leaf4 + +[datacenter:children] +spine +leaf diff --git a/roles/os9_xstp/tests/main.os9.yaml b/roles/os9_xstp/tests/main.os9.yaml new file mode 100644 index 0000000..7f30b08 --- /dev/null +++ b/roles/os9_xstp/tests/main.os9.yaml @@ -0,0 +1,34 @@ +--- +# vars file for dellemc.os9.os9_xstp, +# below gives a sample configuration +# Sample variables for OS9 device +os9_xstp: + type: rstp + enable: true + stp: + bridge_priority: 4096 + state: present + + rstp: + bridge_priority: 4096 + state: present + + pvst: + vlan: + - range_or_id: 10 + bridge_priority: 4096 + state: present + + mstp: + mstp_instances: + - number: 1 + vlans: 10,12 + bridge_priority: 4096 + vlans_state: present + state: present + intf: + fortyGigE 1/25: + stp_type: + - stp + - mstp + edge_port: true \ No newline at end of file diff --git a/roles/os9_xstp/tests/test.yaml b/roles/os9_xstp/tests/test.yaml new file mode 100644 index 0000000..77da967 --- /dev/null +++ b/roles/os9_xstp/tests/test.yaml @@ -0,0 +1,5 @@ +--- +- hosts: datacenter + connection: network_cli + roles: + - dellemc.os9.os9_xstp \ No newline at end of file diff --git a/roles/os9_xstp/vars/main.yml b/roles/os9_xstp/vars/main.yml new file mode 100644 index 0000000..d2fefb0 --- /dev/null +++ b/roles/os9_xstp/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for dellemc.os9.os9_xstp \ No newline at end of file diff --git a/tests/integration/targets/dellos9_config/tests/cli/sublevel.yaml b/tests/integration/targets/dellos9_config/tests/cli/sublevel.yaml deleted file mode 100644 index b8e95d3..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/sublevel.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -- debug: msg="START cli/sublevel.yaml" - -- name: setup test - dellos9_config: - lines: - - 'no ip access-list extended test' - - 'no ip access-list standard test' - provider: "{{ cli }}" - match: none - -- name: configure sub level command - dellos9_config: - lines: ['seq 5 permit ip any any log threshold-in-msgs 10 interval 5'] - parents: ['ip access-list extended test'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'ip access-list extended test' in result.updates" - - "'seq 5 permit ip any any log threshold-in-msgs 10 interval 5' in result.updates" - -- name: configure sub level command idempotent check - dellos9_config: - lines: ['seq 5 permit ip any any log threshold-in-msgs 10 interval 5'] - parents: ['ip access-list extended test'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: teardown - dellos9_config: - lines: - - 'no ip access-list extended test' - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/sublevel.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/sublevel_block.yaml b/tests/integration/targets/dellos9_config/tests/cli/sublevel_block.yaml deleted file mode 100644 index f7b2983..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/sublevel_block.yaml +++ /dev/null @@ -1,62 +0,0 @@ ---- -- debug: msg="START cli/sublevel_block.yaml" - -- name: setup - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - before: ['no ip access-list extended test'] - after: ['exit'] - provider: "{{ cli }}" - match: none - -- name: configure sub level command using block replace - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - replace: block - after: ['exit'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'ip access-list extended test' in result.updates" - - "'seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5' in result.updates" - -- name: check sub level command using block replace - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - replace: block - after: ['exit'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: teardown - dellos9_config: - lines: - - no ip access-list extended test - match: none - provider: "{{ cli }}" - -- debug: msg="END cli/sublevel_block.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/sublevel_exact.yaml b/tests/integration/targets/dellos9_config/tests/cli/sublevel_exact.yaml deleted file mode 100644 index 9c80d3f..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/sublevel_exact.yaml +++ /dev/null @@ -1,66 +0,0 @@ ---- -- debug: msg="START cli/sublevel_exact.yaml" - -- name: setup - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - - seq 25 permit ip host 192.0.2.5 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - before: ['no ip access-list extended test'] - after: ['exit'] - provider: "{{ cli }}" - match: none - -- name: configure sub level command using exact match - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - after: ['exit'] - match: exact - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'ip access-list extended test' in result.updates" - - "'seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 25 permit ip host 192.0.2.5 any log threshold-in-msgs 10 interval 5' not in result.updates" - -- name: check sub level command using exact match - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - - seq 25 permit ip host 192.0.2.5 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - after: ['exit'] - match: exact - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: teardown - dellos9_config: - lines: - - no ip access-list extended test - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/sublevel_exact.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/sublevel_strict.yaml b/tests/integration/targets/dellos9_config/tests/cli/sublevel_strict.yaml deleted file mode 100644 index 3cca5ef..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/sublevel_strict.yaml +++ /dev/null @@ -1,63 +0,0 @@ ---- -- debug: msg="START cli/sublevel_strict.yaml" - -- name: setup - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - - seq 25 permit ip host 192.0.2.5 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - before: ['no ip access-list extended test'] - after: ['exit'] - provider: "{{ cli }}" - match: none - -- name: configure sub level command using strict match - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - match: strict - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: check sub level command using strict match - dellos9_config: - lines: - - seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5 - - seq 10 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5 - - seq 15 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5 - parents: ['ip access-list extended test'] - after: ['exit'] - match: strict - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'ip access-list extended test' in result.updates" - - "'seq 5 permit ip host 192.0.2.1 any log threshold-in-msgs 10 interval 5' not in result.updates" - - "'seq 15 permit ip host 192.0.2.2 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 10 permit ip host 192.0.2.3 any log threshold-in-msgs 10 interval 5' in result.updates" - - "'seq 20 permit ip host 192.0.2.4 any log threshold-in-msgs 10 interval 5' not in result.updates" - - "'seq 25 permit ip host 192.0.2.5 any log threshold-in-msgs 10 interval 5' not in result.updates" - -- name: teardown - dellos9_config: - lines: - - no ip access-list extended test - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/sublevel_strict.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/toplevel_after.yaml b/tests/integration/targets/dellos9_config/tests/cli/toplevel_after.yaml deleted file mode 100644 index 6b5ee8e..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/toplevel_after.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -- debug: msg="START cli/toplevel_after.yaml" - -- name: setup - dellos9_config: - lines: - - "snmp-server contact ansible" - - "hostname {{ inventory_hostname_short }}" - provider: "{{ cli }}" - match: none - -- name: configure top level command with after - dellos9_config: - lines: ['hostname foo'] - after: ['snmp-server contact bar'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'hostname foo' in result.updates" - - "'snmp-server contact bar' in result.updates" - -- name: configure top level command with after idempotent check - dellos9_config: - lines: ['hostname foo'] - after: ['snmp-server contact bar'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: teardown - dellos9_config: - lines: - - "no snmp-server contact" - - "hostname {{ inventory_hostname_short }}" - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/toplevel_after.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/toplevel_before.yaml b/tests/integration/targets/dellos9_config/tests/cli/toplevel_before.yaml deleted file mode 100644 index 79b01e4..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/toplevel_before.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -- debug: msg="START cli/toplevel_before.yaml" - -- name: setup - dellos9_config: - lines: - - "snmp-server contact ansible" - - "hostname {{ inventory_hostname_short }}" - provider: "{{ cli }}" - match: none - -- name: configure top level command with before - dellos9_config: - lines: ['hostname foo'] - before: ['snmp-server contact bar'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == true" - - "'hostname foo' in result.updates" - - "'snmp-server contact bar' in result.updates" - -- name: configure top level command with before idempotent check - dellos9_config: - lines: ['hostname foo'] - before: ['snmp-server contact bar'] - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - -- name: teardown - dellos9_config: - lines: - - "no snmp-server contact" - - "hostname {{ inventory_hostname_short }}" - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/toplevel_before.yaml" diff --git a/tests/integration/targets/dellos9_config/tests/cli/toplevel_nonidempotent.yaml b/tests/integration/targets/dellos9_config/tests/cli/toplevel_nonidempotent.yaml deleted file mode 100644 index 142d5d7..0000000 --- a/tests/integration/targets/dellos9_config/tests/cli/toplevel_nonidempotent.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -- debug: msg="START cli/toplevel_nonidempotent.yaml" - -- name: setup - dellos9_config: - lines: ['hostname {{ inventory_hostname_short }}'] - provider: "{{ cli }}" - match: none - -- name: configure top level command - dellos9_config: - lines: ['hostname foo'] - provider: "{{ cli }}" - match: strict - register: result - -- assert: - that: - - "result.changed == true" - - "'hostname foo' in result.updates" - -- name: configure top level command idempotent check - dellos9_config: - lines: ['hostname foo'] - provider: "{{ cli }}" - match: strict - register: result - -- assert: - that: - - "result.changed == true" - -- name: teardown - dellos9_config: - lines: ['hostname {{ inventory_hostname_short }}'] - provider: "{{ cli }}" - match: none - -- debug: msg="END cli/toplevel_nonidempotent.yaml" diff --git a/tests/integration/targets/dellos9_facts/defaults/main.yaml b/tests/integration/targets/dellos9_facts/defaults/main.yaml deleted file mode 100644 index 5f709c5..0000000 --- a/tests/integration/targets/dellos9_facts/defaults/main.yaml +++ /dev/null @@ -1,2 +0,0 @@ ---- -testcase: "*" diff --git a/tests/integration/targets/dellos9_facts/tasks/main.yaml b/tests/integration/targets/dellos9_facts/tasks/main.yaml deleted file mode 100644 index 415c99d..0000000 --- a/tests/integration/targets/dellos9_facts/tasks/main.yaml +++ /dev/null @@ -1,2 +0,0 @@ ---- -- { include: cli.yaml, tags: ['cli'] } diff --git a/tests/integration/targets/dellos9_facts/tests/cli/facts.yaml b/tests/integration/targets/dellos9_facts/tests/cli/facts.yaml deleted file mode 100644 index acea51c..0000000 --- a/tests/integration/targets/dellos9_facts/tests/cli/facts.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -- debug: msg="START cli/facts.yaml" - -- name: test all facts - dellos9_facts: - gather_subset: - - all - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - - "result.ansible_facts is defined" - -- name: test all facts except hardware - dellos9_facts: - gather_subset: - - "!hardware" - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - - "result.ansible_facts.ansible_net_filesystems is not defined" - -- name: test interface facts - dellos9_facts: - gather_subset: - - interfaces - provider: "{{ cli }}" - register: result - -- assert: - that: - - "result.changed == false" - - "result.ansible_facts.ansible_net_interfaces is defined" - - "result.ansible_facts.ansible_net_filesystems is not defined" - - -- debug: msg="END cli/facts.yaml" diff --git a/tests/integration/targets/os9_command/os9_command/defaults/main.yaml b/tests/integration/targets/os9_command/os9_command/defaults/main.yaml new file mode 100644 index 0000000..55a93fc --- /dev/null +++ b/tests/integration/targets/os9_command/os9_command/defaults/main.yaml @@ -0,0 +1,2 @@ +--- +testcase: "*" \ No newline at end of file diff --git a/tests/integration/targets/dellos9_command/tasks/cli.yaml b/tests/integration/targets/os9_command/os9_command/tasks/cli.yaml similarity index 70% rename from tests/integration/targets/dellos9_command/tasks/cli.yaml rename to tests/integration/targets/os9_command/os9_command/tasks/cli.yaml index 8c11e10..7152815 100644 --- a/tests/integration/targets/dellos9_command/tasks/cli.yaml +++ b/tests/integration/targets/os9_command/os9_command/tasks/cli.yaml @@ -10,7 +10,5 @@ test_items: "{{ test_cases.files | map(attribute='path') | list }}" - name: run test case - include: "{{ test_case_to_run }}" - with_items: "{{ test_items }}" - loop_control: - loop_var: test_case_to_run + include: "{{ item }}" + with_items: "{{ test_items }}" \ No newline at end of file diff --git a/tests/integration/targets/os9_command/os9_command/tasks/main.yaml b/tests/integration/targets/os9_command/os9_command/tasks/main.yaml new file mode 100644 index 0000000..d4898c2 --- /dev/null +++ b/tests/integration/targets/os9_command/os9_command/tasks/main.yaml @@ -0,0 +1,2 @@ +--- +- { include: cli.yaml, tags: ['cli'] } \ No newline at end of file diff --git a/tests/integration/targets/dellos9_command/tests/cli/bad_operator.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/bad_operator similarity index 95% rename from tests/integration/targets/dellos9_command/tests/cli/bad_operator.yaml rename to tests/integration/targets/os9_command/os9_command/tests/cli/bad_operator index 0ec627f..42a164c 100644 --- a/tests/integration/targets/dellos9_command/tests/cli/bad_operator.yaml +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/bad_operator @@ -2,7 +2,7 @@ - debug: msg="START cli/bad_operator.yaml" - name: test bad operator - dellos9_command: + os9_command: commands: - show version - show interfaces TenGigabitEthernet 0/0 diff --git a/tests/integration/targets/dellos9_command/tests/cli/contains.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/contains similarity index 95% rename from tests/integration/targets/dellos9_command/tests/cli/contains.yaml rename to tests/integration/targets/os9_command/os9_command/tests/cli/contains index 4082cdd..2f56a11 100644 --- a/tests/integration/targets/dellos9_command/tests/cli/contains.yaml +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/contains @@ -2,7 +2,7 @@ - debug: msg="START cli/contains.yaml" - name: test contains operator - dellos9_command: + os9_command: commands: - show version - show interface TenGigabitEthernet 0/0 diff --git a/tests/integration/targets/dellos9_command/tests/cli/invalid.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/invalid similarity index 92% rename from tests/integration/targets/dellos9_command/tests/cli/invalid.yaml rename to tests/integration/targets/os9_command/os9_command/tests/cli/invalid index 6e9e8e3..cffc24f 100644 --- a/tests/integration/targets/dellos9_command/tests/cli/invalid.yaml +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/invalid @@ -2,7 +2,7 @@ - debug: msg="START cli/invalid.yaml" - name: run invalid command - dellos9_command: + os9_command: commands: ['show foo'] provider: "{{ cli }}" register: result @@ -13,7 +13,7 @@ - "result.failed" - name: run commands that include invalid command - dellos9_command: + os9_command: commands: - show version - show foo diff --git a/tests/integration/targets/dellos9_command/tests/cli/output.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/output similarity index 93% rename from tests/integration/targets/dellos9_command/tests/cli/output.yaml rename to tests/integration/targets/os9_command/os9_command/tests/cli/output index 151c1b8..1fd5378 100644 --- a/tests/integration/targets/dellos9_command/tests/cli/output.yaml +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/output @@ -2,7 +2,7 @@ - debug: msg="START cli/output.yaml" - name: get output for single command - dellos9_command: + os9_command: commands: ['show version'] provider: "{{ cli }}" register: result @@ -13,7 +13,7 @@ - "result.stdout is defined" - name: get output for multiple commands - dellos9_command: + os9_command: commands: - show version - show interfaces diff --git a/tests/integration/targets/os9_command/os9_command/tests/cli/show_commands.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/show_commands.yaml new file mode 100644 index 0000000..80d1951 --- /dev/null +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/show_commands.yaml @@ -0,0 +1,74 @@ +--- +- debug: msg="START cli/show_commands.yaml" + +- name: test bad operator + os9_command: + commands: + - show version + - show interfaces TenGigabitEthernet 0/0 + wait_for: + - "result[0] contains 'Description : blah'" + provider: "{{ cli }}" + register: result + ignore_errors: yes + +- assert: + that: + - "result.failed == true" + - "result.msg is defined" + +- name: get output for single command + os9_command: + commands: ['show version'] + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.stdout is defined" + +- name: get output for multiple commands + os9_command: + commands: + - show version + - show interfaces + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.stdout is defined" + - "result.stdout | length == 2" + +- name: show run command with grep Option + os9_command: + commands: + - show run | grep username + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.stdout | length == 1" + +- name: Execute multiple show commands continously + os9_command: + commands: + - show system + - show file-systems + - show startup-config + - show tech-support + - show logging + - show system brief | grep Management + provider: "{{ cli }}" + retries: 8 + interval: 5 + register: result + +- assert: + that: + - "result.stdout | length == 6" + +- debug: msg="END cli/show_commands.yaml" diff --git a/tests/integration/targets/dellos9_command/tests/cli/timeout.yaml b/tests/integration/targets/os9_command/os9_command/tests/cli/timeout similarity index 94% rename from tests/integration/targets/dellos9_command/tests/cli/timeout.yaml rename to tests/integration/targets/os9_command/os9_command/tests/cli/timeout index 530ca67..60dbb76 100644 --- a/tests/integration/targets/dellos9_command/tests/cli/timeout.yaml +++ b/tests/integration/targets/os9_command/os9_command/tests/cli/timeout @@ -2,7 +2,7 @@ - debug: msg="START cli/timeout.yaml" - name: test bad condition - dellos9_command: + os9_command: commands: - show version wait_for: diff --git a/tests/integration/targets/dellos9_command/defaults/main.yaml b/tests/integration/targets/os9_config/os9_config/defaults/main.yaml similarity index 100% rename from tests/integration/targets/dellos9_command/defaults/main.yaml rename to tests/integration/targets/os9_config/os9_config/defaults/main.yaml diff --git a/tests/integration/targets/dellos9_config/tasks/cli.yaml b/tests/integration/targets/os9_config/os9_config/tasks/cli.yaml similarity index 78% rename from tests/integration/targets/dellos9_config/tasks/cli.yaml rename to tests/integration/targets/os9_config/os9_config/tasks/cli.yaml index d675462..3e5360a 100644 --- a/tests/integration/targets/dellos9_config/tasks/cli.yaml +++ b/tests/integration/targets/os9_config/os9_config/tasks/cli.yaml @@ -9,7 +9,7 @@ set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: run test case - include: "{{ test_case_to_run }}" + include: "{{ item }}" with_items: "{{ test_items }}" - loop_control: - loop_var: test_case_to_run + + diff --git a/tests/integration/targets/dellos9_config/tasks/main.yaml b/tests/integration/targets/os9_config/os9_config/tasks/main.yaml similarity index 97% rename from tests/integration/targets/dellos9_config/tasks/main.yaml rename to tests/integration/targets/os9_config/os9_config/tasks/main.yaml index 415c99d..aea4ecc 100644 --- a/tests/integration/targets/dellos9_config/tasks/main.yaml +++ b/tests/integration/targets/os9_config/os9_config/tasks/main.yaml @@ -1,2 +1,3 @@ --- - { include: cli.yaml, tags: ['cli'] } + diff --git a/tests/integration/targets/os9_config/os9_config/tests/cli/configcommands.yaml b/tests/integration/targets/os9_config/os9_config/tests/cli/configcommands.yaml new file mode 100644 index 0000000..af4bd8a --- /dev/null +++ b/tests/integration/targets/os9_config/os9_config/tests/cli/configcommands.yaml @@ -0,0 +1,134 @@ +--- +- debug: msg="START cli/config command execution" + +- name: COnfigure managemnet protocol telnet + os9_config: + lines: ['hostname {{ inventory_hostname }}','ip telnet server enable'] + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == true" + +- name: Create new username and set password + os9_config: + lines: ['username test password test123'] + provider: "{{ cli }}" + register: result + +- name: Update the new user test privilige using replace line Option + os9_config: + lines: + - username test password test123 privilege 15 + provider: "{{ cli }}" + replace: line + save: no + register: result + +- name: Validate the newly created username using show run command use the keyword wait_for + os9_command: + commands: + - show running-config | grep username + - show running-config | grep username | grep test + wait_for: + - "result[0] contains test" + provider: "{{ cli }}" + +- name: Configure SNMP v2 credentials on device and enable traps + os9_config: + lines: + - snmp-server community ansibleread ro + - snmp-server community ansiblewrite rw + - snmp-server enable traps + - snmp-server host 10.16.148.142 traps version 2c public udp-port 162 + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == true" + +- name: Validate is newly created snmp v2 is available in running config + os9_command: + commands: + - show running-config | grep snmp-server + wait_for: + - "result[0] contains ansibleread" + - "result[0] contains ansiblewrite" + provider: "{{ cli }}" + register: result + +- name: Configure Clock timezone + os9_config: + lines: "clock timezone UTC 0 0" + provider: "{{ cli }}" + register: result + +- name: Configure Logging to NMS Server + os9_config: + lines: + - logging 10.16.148.142 + #before: + # - no logging 10.16.148.142 + #ignore: yes + provider: "{{ cli }}" + register: result + +- name: Configure Default Gateway + os9_config: + lines: + - management route 0.0.0.0/0 10.16.148.254 + provider: "{{ cli }}" + register: result + + #- assert: + # that: + # - "result.changed == true" + #- "'management route 0.0.0.0/0 10.16.148.254' in result.updates" + +- name: Enable spanning tree protocol using parent , before and after keywords in config module + os9_config: + lines: + - no disable + - hello-time 1 + - max-age 6 + - forward-delay 4 + - bridge-priority 0 + parents: ['protocol spanning-tree rstp'] + before: ['no protocol spanning-tree rstp'] + after: ['exit'] + provider: "{{ cli }}" + register: result + +- name: save the running config into startup config using save keyword in os9 config module + os9_config: + save: yes + provider: "{{ cli }}" + register: result + +- name: Validate the newly added commands are available in startup-config + os9_command: + commands: + - show startup-config + provider: "{{ cli }}" + register: result + +- name: COnfigure new vlan using src file given as input and backup the configuration + os9_config: + src: vlan_config.txt + provider: "{{ cli }}" + update: merge + backup: yes + register: result + + +- name: Validate the check Option for update in Dell os9 config using the config file provided with config option + os9_config: + src: vlan_config.txt + provider: "{{ cli }}" + update: check + config: Aggregation1_config.2016-09-06@15:26:02 + register: result + +- debug: msg="END cli/configcommands" diff --git a/tests/integration/targets/dellos9_config/tests/cli/toplevel.yaml b/tests/integration/targets/os9_config/os9_config/tests/cli/toplevel.yaml similarity index 76% rename from tests/integration/targets/dellos9_config/tests/cli/toplevel.yaml rename to tests/integration/targets/os9_config/os9_config/tests/cli/toplevel.yaml index 22669a4..65df0af 100644 --- a/tests/integration/targets/dellos9_config/tests/cli/toplevel.yaml +++ b/tests/integration/targets/os9_config/os9_config/tests/cli/toplevel.yaml @@ -2,13 +2,13 @@ - debug: msg="START cli/toplevel.yaml" - name: setup - dellos9_config: - lines: ['hostname {{ inventory_hostname_short }}'] + os9_config: + lines: ['hostname {{ inventory_hostname }}'] provider: "{{ cli }}" match: none - name: configure top level command - dellos9_config: + os9_config: lines: ['hostname foo'] provider: "{{ cli }}" register: result @@ -19,7 +19,7 @@ - "'hostname foo' in result.updates" - name: configure top level command idempotent check - dellos9_config: + os9_config: lines: ['hostname foo'] provider: "{{ cli }}" register: result @@ -29,8 +29,8 @@ - "result.changed == false" - name: teardown - dellos9_config: - lines: ['hostname {{ inventory_hostname_short }}'] + os9_config: + lines: ['hostname {{ inventory_hostname }}'] provider: "{{ cli }}" match: none diff --git a/tests/integration/targets/os9_config/os9_config/tests/cli/vlan_config.txt b/tests/integration/targets/os9_config/os9_config/tests/cli/vlan_config.txt new file mode 100644 index 0000000..8940528 --- /dev/null +++ b/tests/integration/targets/os9_config/os9_config/tests/cli/vlan_config.txt @@ -0,0 +1,9 @@ +interface Vlan 1000 + description "vlan added from ansible" + name Testansible-1000 + ip unreachables + ip helper-address 100.1.1.1 + ip udp-helper udp-port 1000 + no shutdown +~ + diff --git a/tests/integration/targets/dellos9_config/defaults/main.yaml b/tests/integration/targets/os9_facts/os9_facts/defaults/main.yaml similarity index 100% rename from tests/integration/targets/dellos9_config/defaults/main.yaml rename to tests/integration/targets/os9_facts/os9_facts/defaults/main.yaml diff --git a/tests/integration/targets/dellos9_facts/tasks/cli.yaml b/tests/integration/targets/os9_facts/os9_facts/tasks/cli.yaml similarity index 57% rename from tests/integration/targets/dellos9_facts/tasks/cli.yaml rename to tests/integration/targets/os9_facts/os9_facts/tasks/cli.yaml index 8c11e10..346bdf2 100644 --- a/tests/integration/targets/dellos9_facts/tasks/cli.yaml +++ b/tests/integration/targets/os9_facts/os9_facts/tasks/cli.yaml @@ -6,11 +6,8 @@ register: test_cases - name: set test_items - set_fact: - test_items: "{{ test_cases.files | map(attribute='path') | list }}" + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: run test case - include: "{{ test_case_to_run }}" + include: "{{ item }}" with_items: "{{ test_items }}" - loop_control: - loop_var: test_case_to_run diff --git a/tests/integration/targets/dellos9_command/tasks/main.yaml b/tests/integration/targets/os9_facts/os9_facts/tasks/main.yaml similarity index 100% rename from tests/integration/targets/dellos9_command/tasks/main.yaml rename to tests/integration/targets/os9_facts/os9_facts/tasks/main.yaml diff --git a/tests/integration/targets/os9_facts/os9_facts/tests/cli/testcases_facts.yaml b/tests/integration/targets/os9_facts/os9_facts/tests/cli/testcases_facts.yaml new file mode 100644 index 0000000..09fa844 --- /dev/null +++ b/tests/integration/targets/os9_facts/os9_facts/tests/cli/testcases_facts.yaml @@ -0,0 +1,56 @@ +--- +- debug: msg="START cli/testcases_facts.yaml" + +- name: Get all the interfaces facts + os9_facts: + gather_subset: + - interfaces + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.ansible_facts is defined" + - "result.ansible_facts.ansible_net_all_ipv4_addresses is defined" + - "result.ansible_facts.ansible_net_interfaces is defined" + - "result.ansible_facts.ansible_net_neighbors is defined" + +- name: Get all the facts Excpet Interfaces using ! Operator and validate + os9_facts: + gather_subset: + - "!interfaces" + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.ansible_facts is defined" + - "result.ansible_facts.ansible_net_all_ipv4_addresses is not defined" + - "result.ansible_facts.ansible_net_interfaces is not defined" + - "result.ansible_facts.ansible_net_neighbors is not defined" + - "result.ansible_facts.ansible_net_config is defined" + - "result.ansible_facts.ansible_net_filesystems is defined" + +- name: Test with multiple subsets provided + os9_facts: + gather_subset: + - config + - hardware + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.ansible_facts is defined" + - "result.ansible_facts.ansible_net_filesystems is defined" + - "result.ansible_facts.ansible_net_memtotal_mb is defined" + - "result.ansible_facts.ansible_net_memfree_mb is defined" + - "result.ansible_facts.ansible_net_config is defined" + + + +- debug: msg="START cli/testcases_facts.yaml" + diff --git a/tests/unit/compat/builtins.py b/tests/unit/compat/builtins.py deleted file mode 100644 index f60ee67..0000000 --- a/tests/unit/compat/builtins.py +++ /dev/null @@ -1,33 +0,0 @@ -# (c) 2014, Toshio Kuratomi -# -# 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 - -# -# Compat for python2.7 -# - -# One unittest needs to import builtins via __import__() so we need to have -# the string that represents it -try: - import __builtin__ -except ImportError: - BUILTINS = 'builtins' -else: - BUILTINS = '__builtin__' diff --git a/tests/unit/compat/mock.py b/tests/unit/compat/mock.py deleted file mode 100644 index 0972cd2..0000000 --- a/tests/unit/compat/mock.py +++ /dev/null @@ -1,122 +0,0 @@ -# (c) 2014, Toshio Kuratomi -# -# 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 - -''' -Compat module for Python3.x's unittest.mock module -''' -import sys - -# Python 2.7 - -# Note: Could use the pypi mock library on python3.x as well as python2.x. It -# is the same as the python3 stdlib mock library - -try: - # Allow wildcard import because we really do want to import all of mock's - # symbols into this compat shim - # pylint: disable=wildcard-import,unused-wildcard-import - from unittest.mock import * -except ImportError: - # Python 2 - # pylint: disable=wildcard-import,unused-wildcard-import - try: - from mock import * - except ImportError: - print('You need the mock library installed on python2.x to run tests') - - -# Prior to 3.4.4, mock_open cannot handle binary read_data -if sys.version_info >= (3,) and sys.version_info < (3, 4, 4): - file_spec = None - - def _iterate_read_data(read_data): - # Helper for mock_open: - # Retrieve lines from read_data via a generator so that separate calls to - # readline, read, and readlines are properly interleaved - sep = b'\n' if isinstance(read_data, bytes) else '\n' - data_as_list = [l + sep for l in read_data.split(sep)] - - if data_as_list[-1] == sep: - # If the last line ended in a newline, the list comprehension will have an - # extra entry that's just a newline. Remove this. - data_as_list = data_as_list[:-1] - else: - # If there wasn't an extra newline by itself, then the file being - # emulated doesn't have a newline to end the last line remove the - # newline that our naive format() added - data_as_list[-1] = data_as_list[-1][:-1] - - for line in data_as_list: - yield line - - def mock_open(mock=None, read_data=''): - """ - A helper function to create a mock to replace the use of `open`. It works - for `open` called directly or used as a context manager. - - The `mock` argument is the mock object to configure. If `None` (the - default) then a `MagicMock` will be created for you, with the API limited - to methods or attributes available on standard file handles. - - `read_data` is a string for the `read` methoddline`, and `readlines` of the - file handle to return. This is an empty string by default. - """ - def _readlines_side_effect(*args, **kwargs): - if handle.readlines.return_value is not None: - return handle.readlines.return_value - return list(_data) - - def _read_side_effect(*args, **kwargs): - if handle.read.return_value is not None: - return handle.read.return_value - return type(read_data)().join(_data) - - def _readline_side_effect(): - if handle.readline.return_value is not None: - while True: - yield handle.readline.return_value - for line in _data: - yield line - - global file_spec - if file_spec is None: - import _io - file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) - - if mock is None: - mock = MagicMock(name='open', spec=open) - - handle = MagicMock(spec=file_spec) - handle.__enter__.return_value = handle - - _data = _iterate_read_data(read_data) - - handle.write.return_value = None - handle.read.return_value = None - handle.readline.return_value = None - handle.readlines.return_value = None - - handle.read.side_effect = _read_side_effect - handle.readline.side_effect = _readline_side_effect() - handle.readlines.side_effect = _readlines_side_effect - - mock.return_value = handle - return mock diff --git a/tests/unit/compat/unittest.py b/tests/unit/compat/unittest.py deleted file mode 100644 index 98f08ad..0000000 --- a/tests/unit/compat/unittest.py +++ /dev/null @@ -1,38 +0,0 @@ -# (c) 2014, Toshio Kuratomi -# -# 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 - -''' -Compat module for Python2.7's unittest module -''' - -import sys - -# Allow wildcard import because we really do want to import all of -# unittests's symbols into this compat shim -# pylint: disable=wildcard-import,unused-wildcard-import -if sys.version_info < (2, 7): - try: - # Need unittest2 on python2.6 - from unittest2 import * - except ImportError: - print('You need unittest2 installed on python2.6.x to run tests') -else: - from unittest import * diff --git a/tests/unit/mock/loader.py b/tests/unit/mock/loader.py deleted file mode 100644 index 0ee47fb..0000000 --- a/tests/unit/mock/loader.py +++ /dev/null @@ -1,116 +0,0 @@ -# (c) 2012-2014, Michael DeHaan -# -# 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 - -from ansible.errors import AnsibleParserError -from ansible.parsing.dataloader import DataLoader -from ansible.module_utils._text import to_bytes, to_text - - -class DictDataLoader(DataLoader): - - def __init__(self, file_mapping=None): - file_mapping = {} if file_mapping is None else file_mapping - assert type(file_mapping) == dict - - super(DictDataLoader, self).__init__() - - self._file_mapping = file_mapping - self._build_known_directories() - self._vault_secrets = None - - def load_from_file(self, path, cache=True, unsafe=False): - path = to_text(path) - if path in self._file_mapping: - return self.load(self._file_mapping[path], path) - return None - - # TODO: the real _get_file_contents returns a bytestring, so we actually convert the - # unicode/text it's created with to utf-8 - def _get_file_contents(self, path): - path = to_text(path) - if path in self._file_mapping: - return (to_bytes(self._file_mapping[path]), False) - else: - raise AnsibleParserError("file not found: %s" % path) - - def path_exists(self, path): - path = to_text(path) - return path in self._file_mapping or path in self._known_directories - - def is_file(self, path): - path = to_text(path) - return path in self._file_mapping - - def is_directory(self, path): - path = to_text(path) - return path in self._known_directories - - def list_directory(self, path): - ret = [] - path = to_text(path) - for x in (list(self._file_mapping.keys()) + self._known_directories): - if x.startswith(path): - if os.path.dirname(x) == path: - ret.append(os.path.basename(x)) - return ret - - def is_executable(self, path): - # FIXME: figure out a way to make paths return true for this - return False - - def _add_known_directory(self, directory): - if directory not in self._known_directories: - self._known_directories.append(directory) - - def _build_known_directories(self): - self._known_directories = [] - for path in self._file_mapping: - dirname = os.path.dirname(path) - while dirname not in ('/', ''): - self._add_known_directory(dirname) - dirname = os.path.dirname(dirname) - - def push(self, path, content): - rebuild_dirs = False - if path not in self._file_mapping: - rebuild_dirs = True - - self._file_mapping[path] = content - - if rebuild_dirs: - self._build_known_directories() - - def pop(self, path): - if path in self._file_mapping: - del self._file_mapping[path] - self._build_known_directories() - - def clear(self): - self._file_mapping = dict() - self._known_directories = [] - - def get_basedir(self): - return os.getcwd() - - def set_vault_secrets(self, vault_secrets): - self._vault_secrets = vault_secrets diff --git a/tests/unit/mock/path.py b/tests/unit/mock/path.py deleted file mode 100644 index ebe2760..0000000 --- a/tests/unit/mock/path.py +++ /dev/null @@ -1,5 +0,0 @@ -from ansible_collections.dellemc_networking.os9.tests.unit.compat.mock import MagicMock -from ansible.utils.path import unfrackpath - - -mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x) diff --git a/tests/unit/mock/procenv.py b/tests/unit/mock/procenv.py deleted file mode 100644 index d5ff79f..0000000 --- a/tests/unit/mock/procenv.py +++ /dev/null @@ -1,90 +0,0 @@ -# (c) 2016, Matt Davis -# (c) 2016, Toshio Kuratomi -# -# 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 sys -import json - -from contextlib import contextmanager -from io import BytesIO, StringIO -from ansible_collections.dellemc_networking.os9.tests.unit.compat import unittest -from ansible.module_utils.six import PY3 -from ansible.module_utils._text import to_bytes - - -@contextmanager -def swap_stdin_and_argv(stdin_data='', argv_data=tuple()): - """ - context manager that temporarily masks the test runner's values for stdin and argv - """ - real_stdin = sys.stdin - real_argv = sys.argv - - if PY3: - fake_stream = StringIO(stdin_data) - fake_stream.buffer = BytesIO(to_bytes(stdin_data)) - else: - fake_stream = BytesIO(to_bytes(stdin_data)) - - try: - sys.stdin = fake_stream - sys.argv = argv_data - - yield - finally: - sys.stdin = real_stdin - sys.argv = real_argv - - -@contextmanager -def swap_stdout(): - """ - context manager that temporarily replaces stdout for tests that need to verify output - """ - old_stdout = sys.stdout - - if PY3: - fake_stream = StringIO() - else: - fake_stream = BytesIO() - - try: - sys.stdout = fake_stream - - yield fake_stream - finally: - sys.stdout = old_stdout - - -class ModuleTestCase(unittest.TestCase): - def setUp(self, module_args=None): - if module_args is None: - module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False} - - args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args)) - - # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually - self.stdin_swap = swap_stdin_and_argv(stdin_data=args) - self.stdin_swap.__enter__() - - def tearDown(self): - # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually - self.stdin_swap.__exit__(None, None, None) diff --git a/tests/unit/mock/vault_helper.py b/tests/unit/mock/vault_helper.py deleted file mode 100644 index dcce9c7..0000000 --- a/tests/unit/mock/vault_helper.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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.module_utils._text import to_bytes - -from ansible.parsing.vault import VaultSecret - - -class TextVaultSecret(VaultSecret): - '''A secret piece of text. ie, a password. Tracks text encoding. - - The text encoding of the text may not be the default text encoding so - we keep track of the encoding so we encode it to the same bytes.''' - - def __init__(self, text, encoding=None, errors=None, _bytes=None): - super(TextVaultSecret, self).__init__() - self.text = text - self.encoding = encoding or 'utf-8' - self._bytes = _bytes - self.errors = errors or 'strict' - - @property - def bytes(self): - '''The text encoded with encoding, unless we specifically set _bytes.''' - return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors) diff --git a/tests/unit/mock/yaml_helper.py b/tests/unit/mock/yaml_helper.py deleted file mode 100644 index cc095fe..0000000 --- a/tests/unit/mock/yaml_helper.py +++ /dev/null @@ -1,121 +0,0 @@ -import io -import yaml - -from ansible.module_utils.six import PY3 -from ansible.parsing.yaml.loader import AnsibleLoader -from ansible.parsing.yaml.dumper import AnsibleDumper - - -class YamlTestUtils(object): - """Mixin class to combine with a unittest.TestCase subclass.""" - def _loader(self, stream): - """Vault related tests will want to override this. - - Vault cases should setup a AnsibleLoader that has the vault password.""" - return AnsibleLoader(stream) - - def _dump_stream(self, obj, stream, dumper=None): - """Dump to a py2-unicode or py3-string stream.""" - if PY3: - return yaml.dump(obj, stream, Dumper=dumper) - else: - return yaml.dump(obj, stream, Dumper=dumper, encoding=None) - - def _dump_string(self, obj, dumper=None): - """Dump to a py2-unicode or py3-string""" - if PY3: - return yaml.dump(obj, Dumper=dumper) - else: - return yaml.dump(obj, Dumper=dumper, encoding=None) - - def _dump_load_cycle(self, obj): - # Each pass though a dump or load revs the 'generation' - # obj to yaml string - string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper) - - # wrap a stream/file like StringIO around that yaml - stream_from_object_dump = io.StringIO(string_from_object_dump) - loader = self._loader(stream_from_object_dump) - # load the yaml stream to create a new instance of the object (gen 2) - obj_2 = loader.get_data() - - # dump the gen 2 objects directory to strings - string_from_object_dump_2 = self._dump_string(obj_2, - dumper=AnsibleDumper) - - # The gen 1 and gen 2 yaml strings - self.assertEqual(string_from_object_dump, string_from_object_dump_2) - # the gen 1 (orig) and gen 2 py object - self.assertEqual(obj, obj_2) - - # again! gen 3... load strings into py objects - stream_3 = io.StringIO(string_from_object_dump_2) - loader_3 = self._loader(stream_3) - obj_3 = loader_3.get_data() - - string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper) - - self.assertEqual(obj, obj_3) - # should be transitive, but... - self.assertEqual(obj_2, obj_3) - self.assertEqual(string_from_object_dump, string_from_object_dump_3) - - def _old_dump_load_cycle(self, obj): - '''Dump the passed in object to yaml, load it back up, dump again, compare.''' - stream = io.StringIO() - - yaml_string = self._dump_string(obj, dumper=AnsibleDumper) - self._dump_stream(obj, stream, dumper=AnsibleDumper) - - yaml_string_from_stream = stream.getvalue() - - # reset stream - stream.seek(0) - - loader = self._loader(stream) - # loader = AnsibleLoader(stream, vault_password=self.vault_password) - obj_from_stream = loader.get_data() - - stream_from_string = io.StringIO(yaml_string) - loader2 = self._loader(stream_from_string) - # loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password) - obj_from_string = loader2.get_data() - - stream_obj_from_stream = io.StringIO() - stream_obj_from_string = io.StringIO() - - if PY3: - yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper) - yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper) - else: - yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None) - yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None) - - yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue() - yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue() - - stream_obj_from_stream.seek(0) - stream_obj_from_string.seek(0) - - if PY3: - yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper) - yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper) - else: - yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None) - yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None) - - assert yaml_string == yaml_string_obj_from_stream - assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string - assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream == - yaml_string_stream_obj_from_string) - assert obj == obj_from_stream - assert obj == obj_from_string - assert obj == yaml_string_obj_from_stream - assert obj == yaml_string_obj_from_string - assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string - return {'obj': obj, - 'yaml_string': yaml_string, - 'yaml_string_from_stream': yaml_string_from_stream, - 'obj_from_stream': obj_from_stream, - 'obj_from_string': obj_from_string, - 'yaml_string_obj_from_string': yaml_string_obj_from_string} diff --git a/tests/unit/modules/conftest.py b/tests/unit/modules/conftest.py deleted file mode 100644 index 3bbfe0b..0000000 --- a/tests/unit/modules/conftest.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2017 Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -import json - -import pytest - -from ansible.module_utils.six import string_types -from ansible.module_utils._text import to_bytes -from ansible.module_utils.common._collections_compat import MutableMapping - - -@pytest.fixture -def patch_ansible_module(request, mocker): - if isinstance(request.param, string_types): - args = request.param - elif isinstance(request.param, MutableMapping): - if 'ANSIBLE_MODULE_ARGS' not in request.param: - request.param = {'ANSIBLE_MODULE_ARGS': request.param} - if '_ansible_remote_tmp' not in request.param['ANSIBLE_MODULE_ARGS']: - request.param['ANSIBLE_MODULE_ARGS']['_ansible_remote_tmp'] = '/tmp' - if '_ansible_keep_remote_files' not in request.param['ANSIBLE_MODULE_ARGS']: - request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = False - args = json.dumps(request.param) - else: - raise Exception('Malformed data to the patch_ansible_module pytest fixture') - - mocker.patch('ansible.module_utils.basic._ANSIBLE_ARGS', to_bytes(args)) diff --git a/tests/unit/modules/network/dellos9/fixtures/show_running-config__grep_hostname b/tests/unit/modules/network/dellos9/fixtures/show_running-config__grep_hostname deleted file mode 100644 index 7c4137c..0000000 --- a/tests/unit/modules/network/dellos9/fixtures/show_running-config__grep_hostname +++ /dev/null @@ -1 +0,0 @@ -hostname dellos9_sw1 diff --git a/tests/unit/modules/utils.py b/tests/unit/modules/utils.py deleted file mode 100644 index 86ea270..0000000 --- a/tests/unit/modules/utils.py +++ /dev/null @@ -1,47 +0,0 @@ -import json - -from ansible_collections.dellemc_networking.os9.tests.unit.compat import unittest -from ansible_collections.dellemc_networking.os9.tests.unit.compat.mock import patch -from ansible.module_utils import basic -from ansible.module_utils._text import to_bytes - - -def set_module_args(args): - if '_ansible_remote_tmp' not in args: - args['_ansible_remote_tmp'] = '/tmp' - if '_ansible_keep_remote_files' not in args: - args['_ansible_keep_remote_files'] = False - - args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) - basic._ANSIBLE_ARGS = to_bytes(args) - - -class AnsibleExitJson(Exception): - pass - - -class AnsibleFailJson(Exception): - pass - - -def exit_json(*args, **kwargs): - if 'changed' not in kwargs: - kwargs['changed'] = False - raise AnsibleExitJson(kwargs) - - -def fail_json(*args, **kwargs): - kwargs['failed'] = True - raise AnsibleFailJson(kwargs) - - -class ModuleTestCase(unittest.TestCase): - - def setUp(self): - self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json) - self.mock_module.start() - self.mock_sleep = patch('time.sleep') - self.mock_sleep.start() - set_module_args({}) - self.addCleanup(self.mock_module.stop) - self.addCleanup(self.mock_sleep.stop) diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt deleted file mode 100644 index a9772be..0000000 --- a/tests/unit/requirements.txt +++ /dev/null @@ -1,42 +0,0 @@ -boto3 -placebo -pycrypto -passlib -pypsrp -python-memcached -pytz -pyvmomi -redis -requests -setuptools > 0.6 # pytest-xdist installed via requirements does not work with very old setuptools (sanity_ok) -unittest2 ; python_version < '2.7' -importlib ; python_version < '2.7' -netaddr -ipaddress -netapp-lib -solidfire-sdk-python - -# requirements for F5 specific modules -f5-sdk ; python_version >= '2.7' -f5-icontrol-rest ; python_version >= '2.7' -deepdiff - -# requirement for Fortinet specific modules -pyFMG - -# requirement for aci_rest module -xmljson - -# requirement for winrm connection plugin tests -pexpect - -# requirement for the linode module -linode-python # APIv3 -linode_api4 ; python_version > '2.6' # APIv4 - -# requirement for the gitlab module -python-gitlab -httmock - -# requirment for kubevirt modules -openshift ; python_version >= '2.7' diff --git a/tests/units/modules/network/os9/__init__.py b/tests/units/modules/network/os9/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/modules/network/dellos9/fixtures/dellos9_config_config.cfg b/tests/units/modules/network/os9/fixtures/os9_config_config.cfg similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/dellos9_config_config.cfg rename to tests/units/modules/network/os9/fixtures/os9_config_config.cfg diff --git a/tests/unit/modules/network/dellos9/fixtures/dellos9_config_src.cfg b/tests/units/modules/network/os9/fixtures/os9_config_src.cfg similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/dellos9_config_src.cfg rename to tests/units/modules/network/os9/fixtures/os9_config_src.cfg diff --git a/tests/unit/modules/network/dellos9/fixtures/show_file-systems b/tests/units/modules/network/os9/fixtures/show_file-systems similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_file-systems rename to tests/units/modules/network/os9/fixtures/show_file-systems diff --git a/tests/unit/modules/network/dellos9/fixtures/show_interfaces b/tests/units/modules/network/os9/fixtures/show_interfaces similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_interfaces rename to tests/units/modules/network/os9/fixtures/show_interfaces diff --git a/tests/unit/modules/network/dellos9/fixtures/show_inventory b/tests/units/modules/network/os9/fixtures/show_inventory similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_inventory rename to tests/units/modules/network/os9/fixtures/show_inventory diff --git a/tests/unit/modules/network/dellos9/fixtures/show_ipv6_interface b/tests/units/modules/network/os9/fixtures/show_ipv6_interface similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_ipv6_interface rename to tests/units/modules/network/os9/fixtures/show_ipv6_interface diff --git a/tests/unit/modules/network/dellos9/fixtures/show_lldp_neighbors_detail b/tests/units/modules/network/os9/fixtures/show_lldp_neighbors_detail similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_lldp_neighbors_detail rename to tests/units/modules/network/os9/fixtures/show_lldp_neighbors_detail diff --git a/tests/unit/modules/network/dellos9/fixtures/show_memory__except_Processor b/tests/units/modules/network/os9/fixtures/show_memory__except_Processor similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_memory__except_Processor rename to tests/units/modules/network/os9/fixtures/show_memory__except_Processor diff --git a/tests/unit/modules/network/dellos9/fixtures/show_running-config b/tests/units/modules/network/os9/fixtures/show_running-config similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_running-config rename to tests/units/modules/network/os9/fixtures/show_running-config diff --git a/tests/units/modules/network/os9/fixtures/show_running-config__grep_hostname b/tests/units/modules/network/os9/fixtures/show_running-config__grep_hostname new file mode 100644 index 0000000..9a2c181 --- /dev/null +++ b/tests/units/modules/network/os9/fixtures/show_running-config__grep_hostname @@ -0,0 +1 @@ +hostname os9_sw1 diff --git a/tests/unit/modules/network/dellos9/fixtures/show_version b/tests/units/modules/network/os9/fixtures/show_version similarity index 100% rename from tests/unit/modules/network/dellos9/fixtures/show_version rename to tests/units/modules/network/os9/fixtures/show_version diff --git a/tests/unit/modules/network/dellos9/dellos9_module.py b/tests/units/modules/network/os9/os9_module.py similarity index 92% rename from tests/unit/modules/network/dellos9/dellos9_module.py rename to tests/units/modules/network/os9/os9_module.py index 0b85946..53be69b 100644 --- a/tests/unit/modules/network/dellos9/dellos9_module.py +++ b/tests/units/modules/network/os9/os9_module.py @@ -1,6 +1,4 @@ -# (c) 2016 Red Hat Inc. -# -# (c) 2017 Dell EMC. +# (c) 2020 Red Hat Inc. # # This file is part of Ansible # @@ -24,7 +22,7 @@ __metaclass__ = type import os import json -from ansible_collections.dellemc_networking.os9.tests.unit.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase +from units.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') @@ -42,7 +40,7 @@ def load_fixture(name): try: data = json.loads(data) - except Exception: + except: pass fixture_data[path] = data diff --git a/tests/unit/modules/network/dellos9/test_dellos9_command.py b/tests/units/modules/network/os9/test_os9_command.py similarity index 79% rename from tests/unit/modules/network/dellos9/test_dellos9_command.py rename to tests/units/modules/network/os9/test_os9_command.py index f9959ba..6353d8f 100644 --- a/tests/unit/modules/network/dellos9/test_dellos9_command.py +++ b/tests/units/modules/network/os9/test_os9_command.py @@ -1,6 +1,4 @@ -# (c) 2016 Red Hat Inc. -# -# (c) 2017 Dell EMC. +# (c) 2020 Red Hat Inc. # # This file is part of Ansible # @@ -23,20 +21,20 @@ __metaclass__ = type import json -from ansible_collections.dellemc_networking.os9.tests.unit.compat.mock import patch -from ansible_collections.dellemc_networking.os9.plugins.modules import dellos9_command -from ansible_collections.dellemc_networking.os9.tests.unit.modules.utils import set_module_args -from ..dellos9_module import TestDellos9Module, load_fixture +from ansible.compat.tests.mock import patch +from ansible_collections.dellemc.os9.plugins.modules import os9_command +from units.modules.utils import set_module_args +from .os9_module import TestDellos9Module, load_fixture class TestDellos9CommandModule(TestDellos9Module): - module = dellos9_command + module = os9_command def setUp(self): super(TestDellos9CommandModule, self).setUp() - self.mock_run_commands = patch('ansible_collections.dellemc_networking.os9.plugins.modules.dellos9_command.run_commands') + self.mock_run_commands = patch('ansible.modules.network.os9.os9_command.run_commands') self.run_commands = self.mock_run_commands.start() def tearDown(self): @@ -61,48 +59,48 @@ class TestDellos9CommandModule(TestDellos9Module): self.run_commands.side_effect = load_from_file - def test_dellos9_command_simple(self): + def test_os9_command_simple(self): set_module_args(dict(commands=['show version'])) result = self.execute_module() self.assertEqual(len(result['stdout']), 1) self.assertTrue(result['stdout'][0].startswith('Dell Real Time')) - def test_dellos9_command_multiple(self): + def test_os9_command_multiple(self): set_module_args(dict(commands=['show version', 'show version'])) result = self.execute_module() self.assertEqual(len(result['stdout']), 2) self.assertTrue(result['stdout'][0].startswith('Dell Real Time')) - def test_dellos9_command_wait_for(self): + def test_os9_command_wait_for(self): wait_for = 'result[0] contains "Dell Real"' set_module_args(dict(commands=['show version'], wait_for=wait_for)) self.execute_module() - def test_dellos9_command_wait_for_fails(self): + def test_os9_command_wait_for_fails(self): wait_for = 'result[0] contains "test string"' set_module_args(dict(commands=['show version'], wait_for=wait_for)) self.execute_module(failed=True) self.assertEqual(self.run_commands.call_count, 10) - def test_dellos9_command_retries(self): + def test_os9_command_retries(self): wait_for = 'result[0] contains "test string"' set_module_args(dict(commands=['show version'], wait_for=wait_for, retries=2)) self.execute_module(failed=True) self.assertEqual(self.run_commands.call_count, 2) - def test_dellos9_command_match_any(self): + def test_os9_command_match_any(self): wait_for = ['result[0] contains "Dell Real"', 'result[0] contains "test string"'] set_module_args(dict(commands=['show version'], wait_for=wait_for, match='any')) self.execute_module() - def test_dellos9_command_match_all(self): + def test_os9_command_match_all(self): wait_for = ['result[0] contains "Dell Real"', 'result[0] contains "Operating System"'] set_module_args(dict(commands=['show version'], wait_for=wait_for, match='all')) self.execute_module() - def test_dellos9_command_match_all_failure(self): + def test_os9_command_match_all_failure(self): wait_for = ['result[0] contains "Dell Real"', 'result[0] contains "test string"'] commands = ['show version', 'show version'] diff --git a/tests/unit/modules/network/dellos9/test_dellos9_config.py b/tests/units/modules/network/os9/test_os9_config.py similarity index 75% rename from tests/unit/modules/network/dellos9/test_dellos9_config.py rename to tests/units/modules/network/os9/test_os9_config.py index 3319686..8c159eb 100644 --- a/tests/unit/modules/network/dellos9/test_dellos9_config.py +++ b/tests/units/modules/network/os9/test_os9_config.py @@ -1,7 +1,5 @@ # -# (c) 2016 Red Hat Inc. -# -# (c) 2017 Dell EMC. +# (c) 2020 Red Hat Inc. # # This file is part of Ansible # @@ -22,26 +20,26 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible_collections.dellemc_networking.os9.tests.unit.compat.mock import patch -from ansible_collections.dellemc_networking.os9.plugins.modules import dellos9_config -from ansible_collections.dellemc_networking.os9.tests.unit.modules.utils import set_module_args -from ..dellos9_module import TestDellos9Module, load_fixture +from ansible.compat.tests.mock import patch +from ansible_collections.dellemc.os9.plugins.modules import os9_config +from units.modules.utils import set_module_args +from .os9_module import TestDellos9Module, load_fixture class TestDellos9ConfigModule(TestDellos9Module): - module = dellos9_config + module = os9_config def setUp(self): super(TestDellos9ConfigModule, self).setUp() - self.mock_get_config = patch('ansible_collections.dellemc_networking.os9.plugins.modules.dellos9_config.get_config') + self.mock_get_config = patch('ansible.modules.network.os9.os9_config.get_config') self.get_config = self.mock_get_config.start() - self.mock_load_config = patch('ansible_collections.dellemc_networking.os9.plugins.modules.dellos9_config.load_config') + self.mock_load_config = patch('ansible.modules.network.os9.os9_config.load_config') self.load_config = self.mock_load_config.start() - self.mock_run_commands = patch('ansible_collections.dellemc_networking.os9.plugins.modules.dellos9_config.run_commands') + self.mock_run_commands = patch('ansible.modules.network.os9.os9_config.run_commands') self.run_commands = self.mock_run_commands.start() def tearDown(self): @@ -51,28 +49,28 @@ class TestDellos9ConfigModule(TestDellos9Module): self.mock_run_commands.stop() def load_fixtures(self, commands=None): - config_file = 'dellos9_config_config.cfg' + config_file = 'os9_config_config.cfg' self.get_config.return_value = load_fixture(config_file) self.load_config.return_value = None - def test_dellos9_config_unchanged(self): - src = load_fixture('dellos9_config_config.cfg') + def test_os9_config_unchanged(self): + src = load_fixture('os9_config_config.cfg') set_module_args(dict(src=src)) self.execute_module() - def test_dellos9_config_src(self): - src = load_fixture('dellos9_config_src.cfg') + def test_os9_config_src(self): + src = load_fixture('os9_config_src.cfg') set_module_args(dict(src=src)) commands = ['hostname foo', 'interface fortyGigE 1/6', 'no ip address'] self.execute_module(changed=True, commands=commands) - def test_dellos9_config_backup(self): + def test_os9_config_backup(self): set_module_args(dict(backup=True)) result = self.execute_module() self.assertIn('__backup__', result) - def test_dellos9_config_save(self): + def test_os9_config_save(self): set_module_args(dict(save=True)) self.execute_module(changed=True) self.assertEqual(self.run_commands.call_count, 1) @@ -82,58 +80,58 @@ class TestDellos9ConfigModule(TestDellos9Module): self.assertDictContainsSubset({'command': 'copy running-config startup-config'}, args[0]) # self.assertIn('copy running-config startup-config\r', args) - def test_dellos9_config_lines_wo_parents(self): + def test_os9_config_lines_wo_parents(self): set_module_args(dict(lines=['hostname foo'])) commands = ['hostname foo'] self.execute_module(changed=True, commands=commands) - def test_dellos9_config_lines_w_parents(self): + def test_os9_config_lines_w_parents(self): set_module_args(dict(lines=['shutdown'], parents=['interface fortyGigE 1/6'])) commands = ['interface fortyGigE 1/6', 'shutdown'] self.execute_module(changed=True, commands=commands) - def test_dellos9_config_before(self): + def test_os9_config_before(self): set_module_args(dict(lines=['hostname foo'], before=['snmp-server contact bar'])) commands = ['snmp-server contact bar', 'hostname foo'] self.execute_module(changed=True, commands=commands, sort=False) - def test_dellos9_config_after(self): + def test_os9_config_after(self): set_module_args(dict(lines=['hostname foo'], after=['snmp-server contact bar'])) commands = ['hostname foo', 'snmp-server contact bar'] self.execute_module(changed=True, commands=commands, sort=False) - def test_dellos9_config_before_after_no_change(self): + def test_os9_config_before_after_no_change(self): set_module_args(dict(lines=['hostname router'], before=['snmp-server contact bar'], after=['snmp-server location chennai'])) self.execute_module() - def test_dellos9_config_config(self): + def test_os9_config_config(self): config = 'hostname localhost' set_module_args(dict(lines=['hostname router'], config=config)) commands = ['hostname router'] self.execute_module(changed=True, commands=commands) - def test_dellos9_config_replace_block(self): + def test_os9_config_replace_block(self): lines = ['description test string', 'test string'] parents = ['interface fortyGigE 1/6'] set_module_args(dict(lines=lines, replace='block', parents=parents)) commands = parents + lines self.execute_module(changed=True, commands=commands) - def test_dellos9_config_match_none(self): + def test_os9_config_match_none(self): lines = ['hostname router'] set_module_args(dict(lines=lines, match='none')) self.execute_module(changed=True, commands=lines) - def test_dellos9_config_match_none(self): + def test_os9_config_match_none(self): lines = ['ip address 1.2.3.4/24', 'description test string'] parents = ['interface fortyGigE 1/6'] set_module_args(dict(lines=lines, parents=parents, match='none')) commands = parents + lines self.execute_module(changed=True, commands=commands, sort=False) - def test_dellos9_config_match_strict(self): + def test_os9_config_match_strict(self): lines = ['ip address 1.2.3.4/24', 'description test string', 'shutdown'] parents = ['interface fortyGigE 1/6'] @@ -141,7 +139,7 @@ class TestDellos9ConfigModule(TestDellos9Module): commands = parents + ['shutdown'] self.execute_module(changed=True, commands=commands, sort=False) - def test_dellos9_config_match_exact(self): + def test_os9_config_match_exact(self): lines = ['ip address 1.2.3.4/24', 'description test string', 'shutdown'] parents = ['interface fortyGigE 1/6'] diff --git a/tests/unit/modules/network/dellos9/test_dellos9_facts.py b/tests/units/modules/network/os9/test_os9_facts.py similarity index 69% rename from tests/unit/modules/network/dellos9/test_dellos9_facts.py rename to tests/units/modules/network/os9/test_os9_facts.py index 2a375d1..c983fb6 100644 --- a/tests/unit/modules/network/dellos9/test_dellos9_facts.py +++ b/tests/units/modules/network/os9/test_os9_facts.py @@ -1,4 +1,4 @@ -# (c) 2016 Red Hat Inc. +# (c) 2020 Red Hat Inc. # # This file is part of Ansible # @@ -21,21 +21,21 @@ __metaclass__ = type import json -from ansible_collections.dellemc_networking.os9.tests.unit.compat.mock import patch -from ansible_collections.dellemc_networking.os9.tests.unit.modules.utils import set_module_args -from ..dellos9_module import TestDellos9Module, load_fixture -from ansible_collections.dellemc_networking.os9.plugins.modules import dellos9_facts +from ansible.compat.tests.mock import patch +from units.modules.utils import set_module_args +from .os9_module import TestDellos9Module, load_fixture +from ansible_collections.dellemc.os9.plugins.modules import os9_facts class TestDellos9Facts(TestDellos9Module): - module = dellos9_facts + module = os9_facts def setUp(self): super(TestDellos9Facts, self).setUp() self.mock_run_command = patch( - 'ansible_collections.dellemc_networking.os9.plugins.modules.dellos9_facts.run_commands') + 'ansible.modules.network.os9.os9_facts.run_commands') self.run_command = self.mock_run_command.start() def tearDown(self): @@ -57,50 +57,51 @@ class TestDellos9Facts(TestDellos9Module): command = item if '|' in command: command = str(command).replace('|', '') - filename = str(command).replace(' ', '_') + filename = str(command).replace(' ', '_') filename = filename.replace('/', '7') output.append(load_fixture(filename)) return output self.run_command.side_effect = load_from_file - def test_dellos9_facts_gather_subset_default(self): + def test_os9_facts_gather_subset_default(self): set_module_args(dict()) result = self.execute_module() ansible_facts = result['ansible_facts'] self.assertIn('hardware', ansible_facts['ansible_net_gather_subset']) self.assertIn('default', ansible_facts['ansible_net_gather_subset']) self.assertIn('interfaces', ansible_facts['ansible_net_gather_subset']) - self.assertEqual('dellos9_sw1', ansible_facts['ansible_net_hostname']) + self.assertEquals('os9_sw1', ansible_facts['ansible_net_hostname']) self.assertIn('fortyGigE 0/24', ansible_facts['ansible_net_interfaces'].keys()) - self.assertEqual(3128820, ansible_facts['ansible_net_memtotal_mb']) - self.assertEqual(3125722, ansible_facts['ansible_net_memfree_mb']) + self.assertEquals(3128820, ansible_facts['ansible_net_memtotal_mb']) + self.assertEquals(3125722, ansible_facts['ansible_net_memfree_mb']) - def test_dellos9_facts_gather_subset_config(self): + def test_os9_facts_gather_subset_config(self): set_module_args({'gather_subset': 'config'}) result = self.execute_module() ansible_facts = result['ansible_facts'] self.assertIn('default', ansible_facts['ansible_net_gather_subset']) self.assertIn('config', ansible_facts['ansible_net_gather_subset']) - self.assertEqual('dellos9_sw1', ansible_facts['ansible_net_hostname']) + self.assertEquals('os9_sw1', ansible_facts['ansible_net_hostname']) self.assertIn('ansible_net_config', ansible_facts) - def test_dellos9_facts_gather_subset_hardware(self): + def test_os9_facts_gather_subset_hardware(self): set_module_args({'gather_subset': 'hardware'}) result = self.execute_module() ansible_facts = result['ansible_facts'] self.assertIn('default', ansible_facts['ansible_net_gather_subset']) self.assertIn('hardware', ansible_facts['ansible_net_gather_subset']) - self.assertEqual(['flash', 'fcmfs', 'nfsmount', 'ftp', 'tftp', 'scp', 'http', 'https'], ansible_facts['ansible_net_filesystems']) - self.assertEqual(3128820, ansible_facts['ansible_net_memtotal_mb']) - self.assertEqual(3125722, ansible_facts['ansible_net_memfree_mb']) + self.assertEquals(['flash','fcmfs','nfsmount','ftp','tftp','scp','http','https'], ansible_facts['ansible_net_filesystems']) + self.assertEquals(3128820, ansible_facts['ansible_net_memtotal_mb']) + self.assertEquals(3125722, ansible_facts['ansible_net_memfree_mb']) - def test_dellos9_facts_gather_subset_interfaces(self): + def test_os9_facts_gather_subset_interfaces(self): set_module_args({'gather_subset': 'interfaces'}) result = self.execute_module() ansible_facts = result['ansible_facts'] self.assertIn('default', ansible_facts['ansible_net_gather_subset']) self.assertIn('interfaces', ansible_facts['ansible_net_gather_subset']) self.assertIn('fortyGigE 0/24', ansible_facts['ansible_net_interfaces'].keys()) - self.assertEqual(['Ma 0/0'], list(ansible_facts['ansible_net_neighbors'].keys())) + self.assertEquals(['Ma 0/0'], ansible_facts['ansible_net_neighbors'].keys()) self.assertIn('ansible_net_interfaces', ansible_facts) +