OS9 Ansible Collections (#2)

* adding OS9 ansible collections

* adding OS9 collections

Co-authored-by: Patil <Komal_uttamrao_Patil@Dell.com>
This commit is contained in:
Komal Uttamrao Patil 2020-07-09 19:29:51 -07:00 committed by GitHub
parent 0f46de1d20
commit 90b090b021
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
344 changed files with 16464 additions and 1408 deletions

201
LICENSE Normal file
View file

@ -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.

View file

@ -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 ## 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

0
docs/os9_ecmp.md Normal file
View file

0
docs/os9_interface.md Normal file
View file

0
docs/os9_lag.md Normal file
View file

0
docs/os9_lldp.md Normal file
View file

0
docs/os9_logging.md Normal file
View file

0
docs/os9_ntp.md Normal file
View file

0
docs/os9_prefix_list.md Normal file
View file

0
docs/os9_sflow.md Normal file
View file

0
docs/os9_snmp.md Normal file
View file

0
docs/os9_system.md Normal file
View file

0
docs/os9_users.md Normal file
View file

0
docs/os9_vlan.md Normal file
View file

0
docs/os9_vlt.md Normal file
View file

0
docs/os9_vrf.md Normal file
View file

0
docs/os9_vrrp.md Normal file
View file

0
docs/os9_xstp.md Normal file
View file

View file

@ -1,16 +1,16 @@
namespace: dellemc_networking
name: os9
version: 0.1.0
readme: README.md
authors: authors:
- Abirami N (github.com/abirami-n) - Senthil Ganesan Ganesan <Senthil_Kumar_Ganesa@Dell.com>
description: null - Komal Patil <Komal_uttamrao_Patil@dell.com>
license: GPL-3.0-or-later
license_file: COPYING
tags: null
dependencies: dependencies:
ansible.netcommon: '>=0.0.1' ansible.netcommon: '>=0.0.1'
repository: https://github.com:ansible-collections/dellemc_networking.os9.git description: Ansible Network Collections for Dell EMC OS9
documentation: https://github.com/ansible-collections/dellemc_networking.os9/tree/master/docs license_file: LICENSE
homepage: https://github.com:ansible-collections/dellemc_networking.os9 name: os9
issues: https://github.com:ansible-collections/dellemc_networking.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'

35
playbooks/README.md Normal file
View file

@ -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`

11
playbooks/datacenter.yaml Normal file
View file

@ -0,0 +1,11 @@
---
- hosts: datacenter
gather_facts: no
connection: network_cli
collections:
- dellemc.os9
roles:
- os9_interface
- os9_bgp
- os9_snmp
- os9_system

10
playbooks/group_vars/all Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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"

20
playbooks/inventory.yaml Normal file
View file

@ -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

View file

@ -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 # This file is part of Ansible
# #
@ -25,9 +25,11 @@ import sys
import copy import copy
from ansible import constants as C 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.action.network import ActionModule as ActionNetworkModule
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import load_provider 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 from ansible.utils.display import Display
display = Display() display = Display()
@ -39,7 +41,7 @@ class ActionModule(ActionNetworkModule):
del tmp # tmp no longer has any effect del tmp # tmp no longer has any effect
module_name = self._task.action.split('.')[-1] 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 socket_path = None
persistent_connection = self._play_context.connection.split('.')[-1] 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') display.warning('provider is unnecessary when using network_cli and will be ignored')
del self._task.args['provider'] del self._task.args['provider']
elif self._play_context.connection == 'local': 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 = copy.deepcopy(self._play_context)
pc.connection = 'network_cli' 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.remote_addr = provider['host'] or self._play_context.remote_addr
pc.port = int(provider['port'] or self._play_context.port or 22) pc.port = int(provider['port'] or self._play_context.port or 22)
pc.remote_user = provider['username'] or self._play_context.connection_user pc.remote_user = provider['username'] or self._play_context.connection_user
@ -65,7 +67,7 @@ class ActionModule(ActionNetworkModule):
pc.become_pass = provider['auth_pass'] pc.become_pass = provider['auth_pass']
display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) 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}) connection.set_options(direct={'persistent_command_timeout': command_timeout})
socket_path = connection.run() socket_path = connection.run()
@ -77,5 +79,17 @@ class ActionModule(ActionNetworkModule):
task_vars['ansible_socket'] = socket_path 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) result = super(ActionModule, self).run(task_vars=task_vars)
return result return result

View file

@ -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 # This file is part of Ansible
# #
@ -21,23 +21,22 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
DOCUMENTATION = ''' DOCUMENTATION = """
--- ---
cliconf: dellos9 cliconf: os9
short_description: Use dellos9 cliconf to run command on Dell OS9 platform short_description: Use os9 cliconf to run command on Dell OS9 platform
description: 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. sending and receiving CLI commands from Dell OS9 network devices.
''' version_added: 2.5
"""
import re import re
import json import json
from itertools import chain from itertools import chain
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils._text import to_bytes, to_text 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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
from ansible.plugins.cliconf import CliconfBase, enable_mode from ansible.plugins.cliconf import CliconfBase, enable_mode
@ -47,7 +46,7 @@ class Cliconf(CliconfBase):
def get_device_info(self): def get_device_info(self):
device_info = {} device_info = {}
device_info['network_os'] = 'dellos9' device_info['network_os'] = 'dellemc.os9.os9'
reply = self.get('show version') reply = self.get('show version')
data = to_text(reply, errors='surrogate_or_strict').strip() data = to_text(reply, errors='surrogate_or_strict').strip()
@ -88,35 +87,3 @@ class Cliconf(CliconfBase):
def get_capabilities(self): def get_capabilities(self):
result = super(Cliconf, self).get_capabilities() result = super(Cliconf, self).get_capabilities()
return json.dumps(result) 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=')#')

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com> # Copyright: (c) 2020, Peter Sprygada <psprygada@ansible.com>
# Copyright: (c) 2016, Dell Inc. # Copyright: (c) 2020, Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

View file

View file

@ -1,8 +1,8 @@
# #
# (c) 2015 Peter Sprygada, <psprygada@ansible.com> # (c) 2020 Peter Sprygada, <psprygada@ansible.com>
# (c) 2017 Red Hat, Inc # (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 code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed. # 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 # 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. # 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._text import to_text
from ansible.module_utils.basic import env_fallback 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.network.common.utils import to_list, ComplexList
from ansible.module_utils.connection import Connection, ConnectionError, exec_command from ansible.module_utils.connection import exec_command
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, ConfigLine from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, ConfigLine
_DEVICE_CONFIGS = {} _DEVICE_CONFIGS = {}
@ -45,7 +45,7 @@ WARNING_PROMPTS_RE = [
r"[\r\n]?\[yes/no\]:\s?$" r"[\r\n]?\[yes/no\]:\s?$"
] ]
dellos9_provider_spec = { os9_provider_spec = {
'host': dict(), 'host': dict(),
'port': dict(type='int'), 'port': dict(type='int'),
'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), '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), 'auth_pass': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS']), no_log=True),
'timeout': dict(type='int'), 'timeout': dict(type='int'),
} }
dellos9_argument_spec = { os9_argument_spec = {
'provider': dict(type='dict', options=dellos9_provider_spec), 'provider': dict(type='dict', options=os9_provider_spec),
} }
dellos9_top_spec = { os9_top_spec = {
'host': dict(removed_in_version=2.9), 'host': dict(removed_in_version=2.9),
'port': dict(removed_in_version=2.9, type='int'), 'port': dict(removed_in_version=2.9, type='int'),
'username': dict(removed_in_version=2.9), '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), 'auth_pass': dict(removed_in_version=2.9, no_log=True),
'timeout': dict(removed_in_version=2.9, type='int'), 'timeout': dict(removed_in_version=2.9, type='int'),
} }
dellos9_argument_spec.update(dellos9_top_spec) os9_argument_spec.update(os9_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
def check_args(module, warnings): def check_args(module, warnings):
@ -122,12 +93,26 @@ def get_config(module, flags=None):
return cfg return cfg
def to_commands(module, commands):
spec = {
'command': dict(key=True),
'prompt': dict(),
'answer': dict()
}
transform = ComplexList(spec, module)
return transform(commands)
def run_commands(module, commands, check_rc=True): def run_commands(module, commands, check_rc=True):
connection = get_connection(module) responses = list()
try: commands = to_commands(module, to_list(commands))
return connection.run_commands(commands=commands, check_rc=check_rc) for cmd in commands:
except ConnectionError as exc: cmd = module.jsonify(cmd)
module.fail_json(msg=to_text(exc)) 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): def load_config(module, commands):

View file

@ -1,8 +1,8 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com> # Copyright: (c) 2020, Peter Sprygada <psprygada@ansible.com>
# Copyright: (c) 2016, Dell Inc. # Copyright: (c) 2020, Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # 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'], 'status': ['preview'],
'supported_by': 'community'} 'supported_by': 'community'}
DOCUMENTATION = ''' DOCUMENTATION = """
--- ---
module: dellos9_command module: os9_command
version_added: "2.2"
author: "Dhivya P (@dhivyap)" author: "Dhivya P (@dhivyap)"
short_description: Run commands on remote devices running Dell OS9 short_description: Run commands on remote devices running Dell OS9
description: description:
@ -25,22 +26,16 @@ description:
argument that will cause the module to wait for a specific condition argument that will cause the module to wait for a specific condition
before returning or timing out if the condition is not met. before returning or timing out if the condition is not met.
- This module does not support running commands in configuration mode. - This module does not support running commands in configuration mode.
Please use M(dellos9_config) to configure Dell OS9 devices. Please use M(os9_config) to configure Dell OS9 devices.
extends_documentation_fragment: extends_documentation_fragment: os9
- dellemc_networking.os9.dellos9
options: options:
commands: commands:
description: 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 configured provider. The resulting output from the command
is returned. If the I(wait_for) argument is provided, the is returned. If the I(wait_for) argument is provided, the
module is not returned until the condition is satisfied or module is not returned until the condition is satisfied or
the number of retries has expired. If a command sent to the the number of retries has expired.
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.
type: list type: list
required: true required: true
wait_for: wait_for:
@ -48,9 +43,10 @@ options:
- List of conditions to evaluate against the output of the - List of conditions to evaluate against the output of the
command. The task will wait for each condition to be true command. The task will wait for each condition to be true
before moving forward. If the conditional is not 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. See examples.
type: list type: list
version_added: "2.2"
match: match:
description: description:
- The I(match) argument is used in conjunction with the - The I(match) argument is used in conjunction with the
@ -61,7 +57,8 @@ options:
satisfied. satisfied.
type: str type: str
default: all default: all
choices: [ 'all', 'any' ] choices: [ all, any ]
version_added: "2.5"
retries: retries:
description: description:
- Specifies the number of retries a command should be tried - Specifies the number of retries a command should be tried
@ -78,49 +75,36 @@ options:
trying the command again. trying the command again.
type: int type: int
default: 1 default: 1
notes: notes:
- This module requires Dell OS9 version 9.10.0.1P13 or above. - This module requires Dell OS9 version 9.10.0.1P13 or above.
- This module requires to increase the ssh connection rate limit. - This module requires to increase the ssh connection rate limit.
Use the following command I(ip ssh connection-rate-limit 60) 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. as well.
"""
'''
EXAMPLES = """ EXAMPLES = """
tasks: tasks:
- name: run show version on remote devices - name: run show version on remote devices
dellos9_command: os9_command:
commands: show version commands: show version
- name: run show version and check to see if output contains OS9 - name: run show version and check to see if output contains OS9
dellos9_command: os9_command:
commands: show version commands: show version
wait_for: result[0] contains OS9 wait_for: result[0] contains OS9
- name: run multiple commands on remote nodes - name: run multiple commands on remote nodes
dellos9_command: os9_command:
commands: commands:
- show version - show version
- show interfaces - show interfaces
- name: run multiple commands and evaluate the output - name: run multiple commands and evaluate the output
dellos9_command: os9_command:
commands: commands:
- show version - show version
- show interfaces - show interfaces
wait_for: wait_for:
- result[0] contains OS9 - result[0] contains OS9
- result[1] contains Loopback - 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 = """ RETURN = """
@ -147,26 +131,39 @@ warnings:
""" """
import time import time
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule 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.parsing import Conditional
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import transform_commands, to_lines from ansible.module_utils.six import string_types
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
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): def parse_commands(module, warnings):
commands = transform_commands(module) command = ComplexList(dict(
command=dict(key=True),
if module.check_mode: prompt=dict(),
for item in list(commands): answer=dict()
if not item['command'].startswith('show'): ), module)
warnings.append( commands = command(module.params['commands'])
'Only show commands are supported when using check mode, not ' for index, item in enumerate(commands):
'executing %s' % item['command'] if module.check_mode and not item['command'].startswith('show'):
) warnings.append(
commands.remove(item) '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 return commands
@ -184,7 +181,7 @@ def main():
interval=dict(default=1, type='int') interval=dict(default=1, type='int')
) )
argument_spec.update(dellos9_argument_spec) argument_spec.update(os9_argument_spec)
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)
@ -197,11 +194,8 @@ def main():
result['warnings'] = warnings result['warnings'] = warnings
wait_for = module.params['wait_for'] or list() 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'] retries = module.params['retries']
interval = module.params['interval'] interval = module.params['interval']
match = module.params['match'] match = module.params['match']
@ -228,6 +222,7 @@ def main():
module.fail_json(msg=msg, failed_conditions=failed_conditions) module.fail_json(msg=msg, failed_conditions=failed_conditions)
result.update({ result.update({
'changed': False,
'stdout': responses, 'stdout': responses,
'stdout_lines': list(to_lines(responses)) 'stdout_lines': list(to_lines(responses))
}) })

View file

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# #
# (c) 2015 Peter Sprygada, <psprygada@ansible.com> # (c) 2020 Peter Sprygada, <psprygada@ansible.com>
# Copyright (c) 2016 Dell Inc. # Copyright (c) 2020 Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # 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 from __future__ import absolute_import, division, print_function
@ -13,9 +13,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.1',
'supported_by': 'community'} 'supported_by': 'community'}
DOCUMENTATION = ''' DOCUMENTATION = """
--- ---
module: dellos9_config module: os9_config
version_added: "2.2"
author: "Dhivya P (@dhivyap)" author: "Dhivya P (@dhivyap)"
short_description: Manage Dell EMC Networking OS9 configuration sections short_description: Manage Dell EMC Networking OS9 configuration sections
description: description:
@ -23,9 +24,7 @@ description:
for segmenting configuration into sections. This module provides for segmenting configuration into sections. This module provides
an implementation for working with OS9 configuration sections in an implementation for working with OS9 configuration sections in
a deterministic way. a deterministic way.
extends_documentation_fragment: extends_documentation_fragment: os9
- dellemc_networking.os9.dellos9
options: options:
lines: lines:
description: description:
@ -127,7 +126,7 @@ options:
suboptions: suboptions:
filename: filename:
description: 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 is not given it will be generated based on the hostname, current time and date
in format defined by <hostname>_config.<current-date>@<current-time> in format defined by <hostname>_config.<current-date>@<current-time>
dir_path: dir_path:
@ -140,21 +139,20 @@ options:
and backup configuration will be copied in C(filename) within I(backup) directory. and backup configuration will be copied in C(filename) within I(backup) directory.
type: path type: path
type: dict type: dict
version_added: "2.8"
notes: notes:
- This module requires Dell OS9 version 9.10.0.1P13 or above. - This module requires Dell OS9 version 9.10.0.1P13 or above.
- This module requires to increase the ssh connection rate limit. - This module requires to increase the ssh connection rate limit.
Use the following command I(ip ssh connection-rate-limit 60) Use the following command I(ip ssh connection-rate-limit 60)
to configure the same. This can also be done with the to configure the same. This can also be done with the
M(dellos9_config) module. M(os9_config) module.
''' """
EXAMPLES = """ EXAMPLES = """
- dellos9_config: - os9_config:
lines: ['hostname {{ inventory_hostname }}'] lines: ['hostname {{ inventory_hostname }}']
provider: "{{ cli }}" provider: "{{ cli }}"
- os9_config:
- dellos9_config:
lines: lines:
- 10 permit ip host 1.1.1.1 any log - 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log - 20 permit ip host 2.2.2.2 any log
@ -164,8 +162,7 @@ EXAMPLES = """
parents: ['ip access-list extended test'] parents: ['ip access-list extended test']
before: ['no ip access-list extended test'] before: ['no ip access-list extended test']
match: exact match: exact
- os9_config:
- dellos9_config:
lines: lines:
- 10 permit ip host 1.1.1.1 any log - 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log - 20 permit ip host 2.2.2.2 any log
@ -174,8 +171,7 @@ EXAMPLES = """
parents: ['ip access-list extended test'] parents: ['ip access-list extended test']
before: ['no ip access-list extended test'] before: ['no ip access-list extended test']
replace: block replace: block
- os9_config:
- dellos9_config:
lines: ['hostname {{ inventory_hostname }}'] lines: ['hostname {{ inventory_hostname }}']
provider: "{{ cli }}" provider: "{{ cli }}"
backup: yes backup: yes
@ -205,13 +201,13 @@ backup_path:
description: The full path to the backup file description: The full path to the backup file
returned: when backup is yes returned: when backup is yes
type: str 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.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.os9.plugins.module_utils.network.os9 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.os9.plugins.module_utils.network.os9 import os9_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.os9.plugins.module_utils.network.os9 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 WARNING_PROMPTS_RE
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig, dumps 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) backup_options=dict(type='dict', options=backup_spec)
) )
argument_spec.update(dellos9_argument_spec) argument_spec.update(os9_argument_spec)
mutually_exclusive = [('lines', 'src'), mutually_exclusive = [('lines', 'src'),
('parents', 'src')] ('parents', 'src')]

View file

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# #
# (c) 2015 Peter Sprygada, <psprygada@ansible.com> # (c) 2020 Peter Sprygada, <psprygada@ansible.com>
# Copyright (c) 2016 Dell Inc. # Copyright (c) 2020 Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # 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 from __future__ import absolute_import, division, print_function
@ -13,9 +13,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.1',
'supported_by': 'community'} 'supported_by': 'community'}
DOCUMENTATION = ''' DOCUMENTATION = """
--- ---
module: dellos9_facts module: os9_facts
version_added: "2.2"
author: "Dhivya P (@dhivyap)" author: "Dhivya P (@dhivyap)"
short_description: Collect facts from remote devices running Dell EMC Networking OS9 short_description: Collect facts from remote devices running Dell EMC Networking OS9
description: description:
@ -24,9 +25,7 @@ description:
base network fact keys with C(ansible_net_<fact>). The facts base network fact keys with C(ansible_net_<fact>). The facts
module will always collect a base set of facts from the device module will always collect a base set of facts from the device
and can enable or disable collection of additional facts. and can enable or disable collection of additional facts.
extends_documentation_fragment: extends_documentation_fragment: os9
- dellemc_networking.os9.dellos9
options: options:
gather_subset: gather_subset:
description: description:
@ -39,24 +38,21 @@ options:
default: [ '!config' ] default: [ '!config' ]
notes: notes:
- This module requires OS9 version 9.10.0.1P13 or above. - This module requires OS9 version 9.10.0.1P13 or above.
- This module requires an increase of the SSH connection rate limit. - This module requires an increase of the SSH connection rate limit.
Use the following command I(ip ssh connection-rate-limit 60) 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 = """ EXAMPLES = """
# Collect all facts from the device # Collect all facts from the device
- dellos9_facts: - os9_facts:
gather_subset: all gather_subset: all
# Collect only the config and default facts # Collect only the config and default facts
- dellos9_facts: - os9_facts:
gather_subset: gather_subset:
- config - config
# Do not collect hardware facts # Do not collect hardware facts
- dellos9_facts: - os9_facts:
gather_subset: gather_subset:
- "!hardware" - "!hardware"
""" """
@ -66,7 +62,6 @@ ansible_net_gather_subset:
description: The list of fact subsets collected from the device description: The list of fact subsets collected from the device
returned: always returned: always
type: list type: list
# default # default
ansible_net_model: ansible_net_model:
description: The model name returned from the device description: The model name returned from the device
@ -88,7 +83,6 @@ ansible_net_image:
description: The image file the device is running description: The image file the device is running
returned: always returned: always
type: str type: str
# hardware # hardware
ansible_net_filesystems: ansible_net_filesystems:
description: All file system names available on the device 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 description: The total memory on the remote device in Mb
returned: when hardware is configured returned: when hardware is configured
type: int type: int
# config # config
ansible_net_config: ansible_net_config:
description: The current active config from the device description: The current active config from the device
returned: when config is configured returned: when config is configured
type: str type: str
# interfaces # interfaces
ansible_net_all_ipv4_addresses: ansible_net_all_ipv4_addresses:
description: All IPv4 addresses configured on the device description: All IPv4 addresses configured on the device
@ -134,8 +126,8 @@ except ImportError:
izip = zip izip = zip
from ansible.module_utils.basic import AnsibleModule 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.os9.plugins.module_utils.network.os9 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 os9_argument_spec, check_args
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
@ -511,7 +503,7 @@ def main():
gather_subset=dict(default=['!config'], type='list') 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, module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)

View file

@ -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 # This file is part of Ansible
# #

201
roles/os9_aaa/LICENSE Normal file
View file

@ -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.

334
roles/os9_aaa/README.md Normal file
View file

@ -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.<terminal>`` | dictionary | Configures the primary or virtual terminal line (see ``<terminal>.*``); value can be console <line_number>, vty <line_number> | os9 |
| ``<terminal>.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 |
| ``<terminal>.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 |
| ``<terminal>.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= <ip_address>
**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.

View file

@ -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"

View file

@ -0,0 +1,2 @@
---
# handlers file for dellemc.os9.os9_aaa

View file

@ -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

View file

@ -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

View file

@ -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 %}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
---
- hosts: datacenter
connection: network_cli
roles:
- dellemc.os9.os9_aaa

View file

@ -0,0 +1,2 @@
---
# vars file for dellemc.os9.os9_aaa

201
roles/os9_acl/LICENSE Normal file
View file

@ -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.

139
roles/os9_acl/README.md Normal file
View file

@ -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= <ip_address>
**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.

View file

@ -0,0 +1,2 @@
---
# defaults file for dellemc.os9.os9_acl

View file

@ -0,0 +1,2 @@
---
# handlers file for dellemc.os9.os9_aaa

View file

@ -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

View file

@ -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

View file

@ -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 %}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
---
- hosts: datacenter
connection: network_cli
roles:
- dellemc.os9.os9_acl

View file

@ -0,0 +1,2 @@
---
# vars file for dellemc.os9.os9_acl

201
roles/os9_bgp/LICENSE Normal file
View file

@ -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.

229
roles/os9_bgp/README.md Normal file
View file

@ -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 (<int> <int>); 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= <ip_address>
**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.

View file

@ -0,0 +1,2 @@
---
# defaults file for dellemc.os9.os9_bgp

View file

@ -0,0 +1,2 @@
---
# handlers file for dellemc.os9.os9_bgp

View file

@ -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

View file

@ -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

View file

@ -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 %}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
---
- hosts: datacenter
connection: network_cli
roles:
- dellemc.os9.os9_bgp

View file

@ -0,0 +1,2 @@
---
# vars file for dellemc.os9.os9_bgp

View file

@ -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.

View file

@ -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 *<host_name>.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= <ip_address>
**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.

View file

@ -0,0 +1,2 @@
---
# defaults file for dellemc.os9.os9_copy_config

View file

@ -0,0 +1,2 @@
---
# handlers file for dellemc.os9.os9_copy_config

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
! Version 10.3.0E
! Last configuration change at May 09 21:47:35 2017
!

View file

@ -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

View file

@ -0,0 +1 @@
---

View file

@ -0,0 +1,5 @@
---
- hosts: localhost
connection: network_cli
roles:
- dellemc.os9.os9_copy_config

View file

@ -0,0 +1,2 @@
---
# vars file for dellemc.os9.os9_copy_config

201
roles/os9_dcb/LICENSE Normal file
View file

@ -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.

138
roles/os9_dcb/README.md Normal file
View file

@ -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= <ip_address>
**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.

View file

@ -0,0 +1,2 @@
---
# defaults file for dellemc.os9.os9_dcb

View file

@ -0,0 +1,2 @@
---
# handlers file for dellemc.os9.os9_dcb

View file

@ -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

View file

@ -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

View file

@ -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 %}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
---
- hosts: datacenter
connection: network_cli
roles:
- dellemc.os9.os9_dcb

View file

@ -0,0 +1,2 @@
---
# vars file for dellemc.os9.os9_dcb

Some files were not shown because too many files have changed in this diff Show more