diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bd6ab1e3eb2..18f012aaf48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -180,9 +180,10 @@ repos: name: Build documentation for collection filter plugins. entry: ansible-doc-extractor --template ansible_collections/arista/avd/docs/templates/plugin-docs.j2 --markdown "ansible_collections/arista/avd/docs/plugins/Filter_plugins/" language: python - types: [python] + types_or: [python, yaml] additional_dependencies: ['ansible-doc-extractor>=0.1.10', 'ansible-core>=2.15.0,<2.18.0'] files: ansible_collections/arista/avd/plugins/filter/ + exclude: ^(ansible_collections/arista/avd/plugins/filter/deprecated_filters.py)$ - id: docs-plugin-lookup name: Build documentation for collection lookup plugins. diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-cvp-eos.svg b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-cvp-eos.svg new file mode 100644 index 00000000000..7c7a1c2ae89 --- /dev/null +++ b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-cvp-eos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-dashboardpng.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-dashboardpng.png new file mode 100644 index 00000000000..c97cb8a40ac Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/aap-dashboardpng.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/add-template.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/add-template.png new file mode 100644 index 00000000000..edae9a69fe8 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/add-template.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/all-hosts.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/all-hosts.png new file mode 100644 index 00000000000..aa8b29ab946 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/all-hosts.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-ee.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-ee.png new file mode 100644 index 00000000000..9f0a50038a2 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-ee.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-source.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-source.png new file mode 100644 index 00000000000..f0c933b8b5b Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/create-source.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/cvp-cc.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/cvp-cc.png new file mode 100644 index 00000000000..83fae4d5321 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/cvp-cc.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-output.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-output.png new file mode 100644 index 00000000000..be5c5ff1233 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-output.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-sync.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-sync.png new file mode 100644 index 00000000000..51d12ac96ca Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-job-sync.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-sync.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-sync.png new file mode 100644 index 00000000000..2f5d62322b6 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/inv-sync.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-output.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-output.png new file mode 100644 index 00000000000..2f2ac030495 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-output.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-updates.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-updates.png new file mode 100644 index 00000000000..1040692d29a Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/job-updates.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/run-job.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/run-job.png new file mode 100644 index 00000000000..f30dc84e945 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/run-job.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-inv.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-inv.png new file mode 100644 index 00000000000..4177af5b3ea Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-inv.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-project.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-project.png new file mode 100644 index 00000000000..a3a75cef588 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/save-project.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-ee.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-ee.png new file mode 100644 index 00000000000..f83fbeb7ec4 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-ee.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-inv.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-inv.png new file mode 100644 index 00000000000..e58ac8003ef Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-inv.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-project.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-project.png new file mode 100644 index 00000000000..e4c52347c6e Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-add-project.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-ee.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-ee.png new file mode 100644 index 00000000000..f1198028ca6 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-ee.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-inv.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-inv.png new file mode 100644 index 00000000000..0a326d0db41 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-inv.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-projects.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-projects.png new file mode 100644 index 00000000000..52279216eb5 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-projects.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-sources.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-sources.png new file mode 100644 index 00000000000..11f549c2c01 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-sources.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-templates.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-templates.png new file mode 100644 index 00000000000..d759c2cc8a2 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/select-templates.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-enabled.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-enabled.png new file mode 100644 index 00000000000..aaac472a211 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-enabled.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-save.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-save.png new file mode 100644 index 00000000000..32df2c045ae Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/survey-save.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-save.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-save.png new file mode 100644 index 00000000000..1a7a29795f6 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-save.png differ diff --git a/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-survey.png b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-survey.png new file mode 100644 index 00000000000..f7bf3867222 Binary files /dev/null and b/ansible_collections/arista/avd/docs/_media/getting-started/aap-avd/template-survey.png differ diff --git a/ansible_collections/arista/avd/docs/getting-started/avd-aap.md b/ansible_collections/arista/avd/docs/getting-started/avd-aap.md new file mode 100644 index 00000000000..b88d80f040e --- /dev/null +++ b/ansible_collections/arista/avd/docs/getting-started/avd-aap.md @@ -0,0 +1,398 @@ + + +# AVD and Ansible Automation Platform + +This guide will walk you through the steps required to get up and running with AVD and Red Hat's Ansible Automation Platform (AAP). AAP is Red Hat's solution to scale automation within an organization, whether by making automation more readily available to team members, adding security capabilities, or simplifying the speed of getting started with Ansible using execution environments. + +## Requirements to get started + +- An accessible lab topology running Arista EOS. +- An AVD project or Git repository with playbooks and an inventory. To get started, you may also use any of our [example topologies](../../examples/single-dc-l3ls/README.md). +- A RHEL instance running AAP. + - If you need access to a RHEL instance, you can join the [developer program](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux/developer-program) to get a copy. + - To get started, you may also sign up for a 60-day [trial license](https://www.redhat.com/en/technologies/management/ansible/trial) for AAP. + +!!! note + This guide leverages AAP version 2.4. The workflows should be similar in newer versions. If there are any questions, please see the official [AAP documentation](https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/2.4). If you notice any errors in this guide, please open an [issue](https://github.com/aristanetworks/avd/issues). + +## Topology + +Our topology leverages two spines and four leaf nodes to create a layer three leaf spine topology. The topology is managed by Arista CloudVision (CV). In our case, the EOS nodes are constantly streaming to CV and gives us the ability to provision the nodes with CV. AAP will act as our controller to communicate any updates to CV, which can then push the updates to our topology. + +![Topology leveraging Ansible Automation Platform to communicate with CloudVision](../_media/getting-started/aap-avd/aap-cvp-eos.svg) + +## AAP Dashboard + +The image below provides an excellent overview of the AAP dashboard. From one pane, we have quick links to hosts, inventories, and breakdowns of recent job executions. The left pane provides us access to anything we may need within AAP. This guide will go through setting up the following items: + +- Execution environments +- Projects +- Inventories +- Job templates +- Surveys + +![AAP Dashboard](../_media/getting-started/aap-avd/aap-dashboardpng.png) + +## Execution environments with Ansible Builder + +Execution environments (EEs) are Red Hat's solution for managing project dependencies. In the past, we used Python virtual environments. The Python virtual environments had pros and cons, but EEs leverage containers to wrap all dependencies within a container. EEs make environments more portable and quicker to replicate between AAP nodes and standalone projects. We will go through an EE build together but it is highly recommended to build your own for your specific requirements. + +### Ansible Builder + +Ansible Builder is a tool developed by the Ansible team to aid in creating EEs. Like any tool, there are a few requirements to get started with Ansible Builder. + +- A development machine with Python installed. +- Ansible builder installed with `pip install ansible-builder`. +- [Podman](https://podman.io/docs/installation) installed on the development machine. + +You can place the Ansible builder dependencies with your current project or leverage a separate project entirely for your EE builds. Please note that this example was created with version 4.9.0 of the AVD collection. Dependencies may change between versions. + +```shell +❯ tree -I venv/ +. +├── execution-environment.yml +├── requirements.txt +└── requirements.yml +``` + +=== "execution-environment.yml" + + ```yaml + --- + version: 3 #(1) + + images: #(2) + base_image: + name: registry.fedoraproject.org/fedora:40 + + dependencies: #(3) + python_interpreter: + package_system: python311 + python_path: /usr/bin/python3.11 + + ansible_core: #(4) + package_pip: ansible-core<2.17.0 + + ansible_runner: #(5) + package_pip: ansible-runner + + galaxy: requirements.yml #(6) + + python: requirements.txt #(7) + + ``` + + 1. We are leveraging Ansible Builder 3.x, which requires version 3 of the definition file. If you leverage an older version of Ansible Builder, you may need to use `version: 1`. + 2. You may use any base container image. Please see the official documentation for more examples. + 3. Specifying what version of Python we would like installed during the container build. + 4. The version of ansible-core you need will greatly depend on your specific workflows. + 5. The `ansible-runner` package is required when building an EE. + 6. This is a pointer to any additional collections we want installed on our container. + 7. This is a pointer to any additional Python packages we require for our workflow. + +=== "requirements.yml" + + ```yaml + --- + collections: #(1) + - name: arista.avd + version: 4.9.0 + + ``` + + 1. Installing the `arista.avd` collection for this workflow will ensure that any other required collections are also installed. + +=== "requirements.txt" + + ```text + pyavd[ansible-collection]==4.9.0 + + ``` + + The Python dependencies listed here are from the [collection installation](../../docs/installation/collection-installation.md#python-requirements-installation) instructions. Please update the requirements for the specific version of the `arista.avd` collection you are leveraging. + +#### Build the image + +The command below will use Ansible Builder to start building our custom EE. In this case, we leverage Podman as a container runtime and tag the image appropriately. + +```shell +ansible-builder build --container-runtime podman -v 3 --tag username/image-name +``` + +Once complete, you can push the image to a public or private container registry. + +```shell +podman push IMAGEID docker://docker.io/username/image-name +``` + +!!! note + This guide uses Docker Hub as the container registry, but you may use any container registry that is accessible by AAP. + +### Execution environments on AAP + +Once the image is located on our container registry, we are ready to add our custom EE to AAP. + +=== "Click on EE" + + Scroll down on the left pane, and under `Administration`, click on `Execution Environments`. + + ![Select execution environment](../_media/getting-started/aap-avd/select-ee.png) + +=== "EE - Add" + + In the new pane, click on `Add`. You can also see the built-in EEs installed with AAP. + + ![Select add](../_media/getting-started/aap-avd/select-add-ee.png) + +=== "EE - Save" + + Give the EE an appropriate `Name` and full `Image` location. For the `Pull` option, this will vary if the EE is in active development and frequent changes are expected. Since our EE is in development, we will set this to `Always pull container before running`. + + ![Create EE](../_media/getting-started/aap-avd/create-ee.png) + +## Projects + +Projects in AAP are vital in setting up additional options. For example, we can leverage our project when defining a new inventory or reference playbooks within the project to define job workflows in AAP. + +=== "Click on Projects" + + Scroll up on the left pane, and under `Resources`, click on `Projects`. + + ![Select execution environment](../_media/getting-started/aap-avd/select-projects.png) + +=== "Projects - Add" + + In the new pane, click on `Add`. + + ![Add project](../_media/getting-started/aap-avd/select-add-project.png) + +=== "Projects - Save" + + Give the project an appropriate `Name`. Again, you may use any examples hosted within the [AVD repository](https://github.com/aristanetworks/avd/tree/devel/ansible_collections/arista/avd/examples) or any current project you have. This example will leverage a Git repository as the `Source Control Type`. We will also set the URL for our Git project and, optionally, an alternate branch. Finally, we also check `Update Revision on Launch` and set the `Cache Timeout` to zero. Setting it to zero will also ensure the project updates when running a job that references this project, which is helpful for any projects with active development. + + ![Create EE](../_media/getting-started/aap-avd/save-project.png) + +## Inventories + +AAP provides many ways to add an inventory. For example, we can use an inventory hosted within our project or constructed inventories made from multiple inventories. This example will leverage one inventory from our Git project. + +=== "Click on Inventories" + + On the left pane, and under `Resources`, click on `Inventories`. + + ![Select execution environment](../_media/getting-started/aap-avd/select-inv.png) + +=== "Inventories - Add" + + In the new pane, click on `Add` and select `Add inventory`. + + ![Add inventory](../_media/getting-started/aap-avd/select-add-inv.png) + +=== "Inventories - Save" + + Give the inventory an appropriate `Name` and click `Save`. + + ![Create inventory](../_media/getting-started/aap-avd/save-inv.png) + +### Inventory Sources + +At this point, we have an inventory with no hosts. This is where inventory sources come into play. Like most things, we have a series of options. We can leverage an inventory source from Cloud providers, virtualization platforms, or, in our case, directly from our project. + +=== "Click on Sources" + + On the center pane, click on `Sources`. + + ![Select sources](../_media/getting-started/aap-avd/select-sources.png) + +=== "Sources - Add" + + - In the new pane, click on `Add`. + - A new pane is shown but similar to before, fill in an appropriate `Name` and select `Source from a Project` under `source`. + - Under `Source details` click on the search icon under `Project` + - Select your newly created project + - Under `Source details`, if the `Inventory file` drop-down does not show your inventory, feel free to enter it manually. + - Under `Update options`: + - `Overwrite` is checked. Overwrite will ensure our inventory source manages additions and removal of hosts and groups. + - `Update on launch` is checked. + - Scroll down and click `Save`. + + ![Create source](../_media/getting-started/aap-avd/create-source.png) + +=== "Sources - Sync" + + In the new pane, click on `Sync` to update your inventory. + + ![Inventory sync](../_media/getting-started/aap-avd/inv-sync.png) + +### View the Inventory + +There are a few locations to view the inventory, but for simplicity, we can view it by clicking on `Hosts` on the left pane. + +=== "Click on Sync Job" + + - On the left pane, click on `Jobs`. + - You should see an inventory sync running or complete. + - Click on the inventory sync job. + + ![Inventory job sync](../_media/getting-started/aap-avd/inv-job-sync.png) + +=== "Sync job output" + + Towards the bottom of the output, we see that AAP successfully parsed our inventory. In this case, we have loaded nine groups and seven hosts. + + ![Sync job output](../_media/getting-started/aap-avd/inv-job-output.png) + +=== "Hosts" + + There are a few locations to view the inventory, but for simplicity, we can take a look by clicking on `Hosts` on the left pane. + + ![View inventory](../_media/getting-started/aap-avd/all-hosts.png) + +## Job templates and workflow templates + +One thing that may need some clarification is the naming of "job templates." These map to playbooks within our project. There is also an option to build workflow templates: a series of job templates with some control logic built-in. For this example, we will use a job template to build and deploy our node configurations with CV. + +=== "Click on Templates" + + On the left pane, click on `Templates`. + + ![Click on Templates](../_media/getting-started/aap-avd/select-templates.png) + +=== "Templates - Add" + + - On the center pane, select `Add`. + - In the drop down select `Add job template`. + + ![Add template](../_media/getting-started/aap-avd/add-template.png) + +=== "Templates - Job" + + The job template is where we leverage the custom execution environment. Since our setup requires specific Ansible collections and Python packages installed, we would like to use a pre-packaged environment with that software. We can modify a decent number of settings, and they may look familiar from previous history with Ansible configurations. If you need a refresher on these options, please see the [official documentation](https://docs.ansible.com/automation-controller/latest/html/userguide/job_templates.html). Once you are happy with the settings, click `Save`. + + !!! warning + The playbook is set to "Run," and the EOS instances in use will be changed. Please ensure you are leveraging nonproduction instances when testing. + + ![Template save](../_media/getting-started/aap-avd/template-save.png) + +### Surveys + +With most jobs, we need a way to authenticate to our CV instance or EOS nodes. AAP provides a multitude of ways to define credentials. Some options are credentials for Network devices, Container registries, HashiCorp Vault, etc. Feel free to explore any option you need for your environment. For this guide, we will leverage a survey secret. Surveys allow us to ask users for information we require for a job to execute correctly. We will leverage a survey with a default secret value (this is the credential used to connect to our nodes). + +!!! note + You will need to create a service account and token in CloudVision for the survey. + +=== "Surveys" + + On the center pane, click on `Survey`. + + ![Click on Survey](../_media/getting-started/aap-avd/template-survey.png) + +=== "Surveys - Save" + + - On the center pane, select `Add`. + - Set `Question` to an appropriate value. + - Set `Answer variable name` to any valid variable name, here we use `lab_token`. + - `Answer type` is set to `Password` and the default value is set. + - Set `Maximum length` to 2000 to fit the Service account token for CV provisioning. + - Enter your `Default answer`. + - Click `Save` when done. + + ![Survey save](../_media/getting-started/aap-avd/survey-save.png) + + The `lab_token` variable will be leveraged when provisioning the fabric with the `cv_deploy` role. + + ```yaml + tasks: + - name: Provision CV with AVD configuration + import_role: + name: cv_deploy + vars: + cv_server: + cv_token: "{{ lab_token }}" + cv_run_change_control: true + ``` + + !!! note + This guide leverages the `cv_deploy` role for provisioning through CV. The `cv_deploy` role requires additional options and tokens to be generated. Please see the `cv_deploy` role [documentation](https://avd.arista.com/stable/roles/cv_deploy/index.html) for the most up-to-date settings. We also set `cv_change_control` to `true`, the default it `false`. This allows the change control to be executed automatically. + +=== "Surveys - Enable" + + Click the `Surveys Disabled` radio button to ensure the survey is enabled. + + ![Survey enable](../_media/getting-started/aap-avd/survey-enabled.png) + +### Running the Template with CV + +Below is an example of the playbook we are leveraging to build and deploy our configurations with CV. + +```yaml +--- +- name: Manage Arista EOS EVPN/VXLAN Configuration + hosts: ATD_FABRIC + connection: local + gather_facts: false + collections: + - arista.avd + vars: + fabric_dir_name: "{{ fabric_name }}" + tasks: + + - name: Generate intended variables + import_role: + name: eos_designs + + - name: Generate device intended config and documentation + import_role: + name: eos_cli_config_gen + + - name: Provision nodes with CV + import_role: + name: cv_deploy + vars: + cv_server: + cv_token: "{{ lab_token }}" + cv_run_change_control: true + +``` + +We have everything we need to run our job template now. + +!!! note + This guide leverages the `cv_deploy` role for provisioning through CV. The `cv_deploy` role requires additional options and tokens to be generated. Please see the `cv_deploy` role [documentation](https://avd.arista.com/stable/roles/cv_deploy/index.html) for the most up-to-date settings. We also set `cv_change_control` to `true`, the default it `false`. This allows the change control to be executed automatically. + +=== "Templates Run" + + - On the left pane, click on `Templates`. + - Click on the `Launch Template` icon to run the job template. + - In the new pane, click `Next`. + - In the `Launch` pane, click `Launch`. + + ![Run job](../_media/getting-started/aap-avd/run-job.png) + +=== "Jobs" + + On the left pane, select `Jobs`. You may see a series of updates. For example, our source control is updating because our timeout is set to zero. The inventory has also been updating since we checked `Update on launch`. Last but not least, the job template will run. + + ![Job updates](../_media/getting-started/aap-avd/job-updates.png) + +=== "Job - Output" + + We can now click on the job run and see a successful execution. + + ![Job output](../_media/getting-started/aap-avd/job-output.png) + +=== "CV View" + + From CV's perspective, we can see our change control workflow has been completed for us when leveraging the `cv_deploy` role. + + ![CV Change Controls](../_media/getting-started/aap-avd/cvp-cc.png) + +## References + +- [Ansible Builder documentation](https://ansible.readthedocs.io/projects/builder/en/latest/) +- [Getting started with Execution Environments](https://docs.ansible.com/ansible/latest/getting_started_ee/index.html) +- [Red Hat Ansible Automation Platform Installation Guide](https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/2.0-ea/html/red_hat_ansible_automation_platform_installation_guide/index) diff --git a/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/_emit_warning.md b/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/_emit_warning.md new file mode 100644 index 00000000000..0a48ad9071c --- /dev/null +++ b/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/_emit_warning.md @@ -0,0 +1,44 @@ +--- +# This title is used for search results +title: arista.avd._emit_warning +--- + + +# _emit_warning + +!!! note + Always use the FQCN (Fully Qualified Collection Name) `arista.avd._emit_warning` when using this plugin. + +Internal module - DO NOT USE - Emit a warning in a task. + +## Synopsis + +Emit a warning in a task. + +## Parameters + +| Argument | Type | Required | Default | Value Restrictions | Description | +| -------- | ---- | -------- | ------- | ------------------ | ----------- | +| message | str | optional | None | | The warning message to emit. | + +## Examples + +```yaml +--- +- name: Emit a warning + arista.avd._emit_warning: + message |- + The warning message. + delegate_to: localhost + check_mode: false + run_once: true + changed_when: false +``` + +## Authors + +- Arista Networks (@aristanetworks) diff --git a/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/emit_warning.md b/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/emit_warning.md new file mode 100644 index 00000000000..78c432a45fb --- /dev/null +++ b/ansible_collections/arista/avd/docs/plugins/Modules_and_action_plugins/emit_warning.md @@ -0,0 +1,44 @@ +--- +# This title is used for search results +title: arista.avd.emit_warning +--- + + +# emit_warning + +!!! note + Always use the FQCN (Fully Qualified Collection Name) `arista.avd.emit_warning` when using this plugin. + +Emit a warning in a task. + +## Synopsis + +Emit a warning in a task. + +## Parameters + +| Argument | Type | Required | Default | Value Restrictions | Description | +| -------- | ---- | -------- | ------- | ------------------ | ----------- | +| message | str | optional | None | | The warning message to emit. | + +## Examples + +```yaml +--- +- name: Enit a warning + arista.avd.emit_warning: + message |- + The warning message. + delegate_to: localhost + check_mode: false + run_once: true + changed_when: false +``` + +## Authors + +- EMEA AS Team (@aristanetworks) diff --git a/ansible_collections/arista/avd/docs/release-notes/4.x.x.md b/ansible_collections/arista/avd/docs/release-notes/4.x.x.md index 59956f4ca31..769874a6aa0 100644 --- a/ansible_collections/arista/avd/docs/release-notes/4.x.x.md +++ b/ansible_collections/arista/avd/docs/release-notes/4.x.x.md @@ -12,7 +12,12 @@ title: Release Notes for AVD 4.x.x - Documentation for AVD version `4.x.x` [available here](https://www.avd.sh/en/stable/) - +## Release 4.10.0 + +### Deprecations + +- In AVD version 5.0.0, the `eos_designs.jsonschema.json` and `eos_cli_config_gen.jsonschema.json` will no longer be generated. These schemas are not being used and have never been complete. + ## Release 4.9.0 ### Breaking or behavioral changes in eos_designs @@ -56,6 +61,9 @@ Pull request: - `arista.avd.validate_and_template` - `arista.avd.yaml_templates_to_facts` +- Starting AVD 5.0.0, `eos_validate_state` will use ANTA as backend, which will change the default behavior (same as setting `use_anta: true` in older versions). + Please review the changes described on the ANTA integration page. + ### Fixed issues in eos_cli_config_gen - Fix(eos_cli_config_gen): Fix the templates for event-handlers by @Shivani-gslab in https://github.com/aristanetworks/avd/pull/4055 diff --git a/ansible_collections/arista/avd/docs/semantic-versioning.md b/ansible_collections/arista/avd/docs/semantic-versioning.md index 506195991ab..36c0e700b17 100644 --- a/ansible_collections/arista/avd/docs/semantic-versioning.md +++ b/ansible_collections/arista/avd/docs/semantic-versioning.md @@ -63,6 +63,7 @@ All roles input variables follow SemVer. Any breaking changes will, at a minimum | Action: `validate_and_template` | ✘ | ✘ | Internal plugin, not intended for external use. | | Action: `verify_requirements` | ✘ | ✘ | Internal plugin, not intended for external use. | | Action: `yaml_templates_to_facts` | ✘ | ✘ | Internal plugin, not intended for external use. | +| Action: `_emit_warning` | ✘ | ✘ | Internal plugin, not intended for external use. | | Test: `contains` | ✅ | ✅ | | | Test: `defined` | ✅ | ✅ | | | Test: `global_vars` | ✅ | ✅ | | diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/tunnel-interfaces.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/tunnel-interfaces.md index c63159d2f2e..9c795fea875 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/tunnel-interfaces.md +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/tunnel-interfaces.md @@ -41,12 +41,12 @@ interface Management1 #### Tunnel Interfaces Summary -| Interface | Description | VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | -| --------- | ----------- | --- | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | -| Tunnel1 | test ipv4 only | Tunnel-VRF | 1500 | False | - | ipsec | Ethernet42 | 6.6.6.6 | True | - | -| Tunnel2 | test ipv6 only | default | - | True | NAT-PROFILE-NO-VRF-2 | gre | Ethernet42 | dead:beef::1 | False | Profile-2 | -| Tunnel3 | test dual stack | default | 1500 | - | - | ipsec | Ethernet42 | 1.1.1.1 | - | Profile-3 | -| Tunnel4 | test no tcp_mss | default | 1500 | - | NAT-PROFILE-NO-VRF-1 | - | Ethernet42 | 1.1.1.1 | - | - | +| Interface | Description | VRF | Underlay VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | +| --------- | ----------- | --- | ------------ | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | +| Tunnel1 | test ipv4 only | Tunnel-VRF | Underlay-VRF | 1500 | False | - | ipsec | Ethernet42 | 6.6.6.6 | True | - | +| Tunnel2 | test ipv6 only | default | default | - | True | NAT-PROFILE-NO-VRF-2 | gre | Ethernet42 | dead:beef::1 | False | Profile-2 | +| Tunnel3 | test dual stack | default | default | 1500 | - | - | ipsec | Ethernet42 | 1.1.1.1 | - | Profile-3 | +| Tunnel4 | test no tcp_mss | default | default | 1500 | - | NAT-PROFILE-NO-VRF-1 | - | Ethernet42 | 1.1.1.1 | - | - | ##### IPv4 @@ -80,6 +80,7 @@ interface Tunnel1 tunnel mode ipsec tunnel source interface Ethernet42 tunnel destination 6.6.6.6 + tunnel underlay vrf Underlay-VRF tunnel path-mtu-discovery comment Comment created from eos_cli under tunnel_interfaces.Tunnel1 diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/tunnel-interfaces.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/tunnel-interfaces.cfg index b0a50656da3..f277e807e7f 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/tunnel-interfaces.cfg +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/tunnel-interfaces.cfg @@ -24,6 +24,7 @@ interface Tunnel1 tunnel mode ipsec tunnel source interface Ethernet42 tunnel destination 6.6.6.6 + tunnel underlay vrf Underlay-VRF tunnel path-mtu-discovery comment Comment created from eos_cli under tunnel_interfaces.Tunnel1 diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/tunnel-interfaces.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/tunnel-interfaces.yml index c910e73ae7a..93f9eb48f54 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/tunnel-interfaces.yml +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/tunnel-interfaces.yml @@ -5,6 +5,7 @@ tunnel_interfaces: description: test ipv4 only shutdown: false vrf: Tunnel-VRF + underlay_vrf: Underlay-VRF mtu: 1500 ip_address: 42.42.42.42/24 access_group_in: test-in diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/documentation/devices/host1.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/documentation/devices/host1.md index 3cc891fb02b..74529a2c01f 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/documentation/devices/host1.md +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/documentation/devices/host1.md @@ -721,6 +721,7 @@ interface Ethernet47 | Interface | Description | Type | Mode | VLANs | Native VLAN | Trunk Group | LACP Fallback Timeout | LACP Fallback Mode | MLAG ID | EVPN ESI | | --------- | ----------- | ---- | ---- | ----- | ----------- | ------------| --------------------- | ------------------ | ------- | -------- | | Port-Channel1 | SRV01_bond0 | switched | trunk | 2-3000 | - | - | - | - | - | 0000:0000:0404:0404:0303 | +| Port-Channel30 | deprecate_filters_testing | switched | access | - | - | - | - | - | - | deaf:beed:0303:0202:0101 | | Port-Channel51 | ipv6_prefix | switched | trunk | 1-500 | - | - | - | - | - | - | ##### Flexible Encapsulation Interfaces @@ -757,6 +758,14 @@ interface Port-Channel2.1000 route-target import 03:03:02:02:01:01 lacp system-id 0303.0202.0101 ! +interface Port-Channel30 + description deprecate_filters_testing + switchport + evpn ethernet-segment + identifier deaf:beed:0303:0202:0101 + route-target import 03:03:02:02:01:01 + lacp system-id 0303.0202.0101 +! interface Port-Channel51 description ipv6_prefix switchport @@ -804,10 +813,10 @@ interface Loopback1 #### Tunnel Interfaces Summary -| Interface | Description | VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | -| --------- | ----------- | --- | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | -| Tunnel3 | test dual stack | default | 1500 | - | - | - | Ethernet42 | 1.1.1.1 | - | - | -| Tunnel4 | test no tcp_mss | default | 1500 | - | - | - | Ethernet42 | 1.1.1.1 | - | - | +| Interface | Description | VRF | Underlay VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | +| --------- | ----------- | --- | ------------ | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | +| Tunnel3 | test dual stack | default | default | 1500 | - | - | - | Ethernet42 | 1.1.1.1 | - | - | +| Tunnel4 | test no tcp_mss | default | default | 1500 | - | - | - | Ethernet42 | 1.1.1.1 | - | - | ##### IPv4 diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/intended/configs/host1.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/intended/configs/host1.cfg index 5405be908d7..244ea675c32 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/intended/configs/host1.cfg +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/intended/configs/host1.cfg @@ -170,6 +170,14 @@ interface Port-Channel2.1000 route-target import 03:03:02:02:01:01 lacp system-id 0303.0202.0101 ! +interface Port-Channel30 + description deprecate_filters_testing + switchport + evpn ethernet-segment + identifier deaf:beed:0303:0202:0101 + route-target import 03:03:02:02:01:01 + lacp system-id 0303.0202.0101 +! interface Port-Channel51 description ipv6_prefix switchport diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/host_vars/host1/port-channel-interfaces.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/host_vars/host1/port-channel-interfaces.yml index 78720cb676a..bcdf9b75f00 100644 --- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/host_vars/host1/port-channel-interfaces.yml +++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/host_vars/host1/port-channel-interfaces.yml @@ -30,6 +30,14 @@ port_channel_interfaces: rt: 03:03:02:02:01:01 lacp_id: 0303.0202.0101 + # Testing deprecated filter plugins to be remove in AVD 5.0.0 + Port-Channel30: + description: deprecate_filters_testing + esi: "{{ '0303:0202:0101' | arista.avd.generate_esi('deaf:beed:') }}" + rt: "{{ '0303:0202:0101' | arista.avd.generate_route_target }}" + lacp_id: "{{ '0303:0202:0101' | arista.avd.generate_lacp_id }}" + + Port-Channel51: description: ipv6_prefix vlans: 1-500 diff --git a/ansible_collections/arista/avd/molecule/eos_validate_state/converge.yml b/ansible_collections/arista/avd/molecule/eos_validate_state/converge.yml index fbbb8c60e51..cc6596ed77f 100644 --- a/ansible_collections/arista/avd/molecule/eos_validate_state/converge.yml +++ b/ansible_collections/arista/avd/molecule/eos_validate_state/converge.yml @@ -15,7 +15,6 @@ delegate_to: localhost ansible.builtin.import_role: name: arista.avd.eos_validate_state - # Save catalogs vars: use_anta: true save_catalog: true diff --git a/ansible_collections/arista/avd/plugins/action/_emit_warning.py b/ansible_collections/arista/avd/plugins/action/_emit_warning.py new file mode 100644 index 00000000000..c52eb00472b --- /dev/null +++ b/ansible_collections/arista/avd/plugins/action/_emit_warning.py @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +"""Temporary file to emit a warning.""" + +from ansible.plugins.action import ActionBase +from ansible.utils.display import Display + +display = Display() + +__metaclass__ = type + + +class ActionModule(ActionBase): + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = {} + + result = super().run(tmp, task_vars) + del tmp + + if self._task.args: + message = self._task.args.get("message") + + display.warning(message) + + return result diff --git a/ansible_collections/arista/avd/plugins/action/eos_cli_config_gen.py b/ansible_collections/arista/avd/plugins/action/eos_cli_config_gen.py index b36d3c22842..a7cc2732a09 100644 --- a/ansible_collections/arista/avd/plugins/action/eos_cli_config_gen.py +++ b/ansible_collections/arista/avd/plugins/action/eos_cli_config_gen.py @@ -188,7 +188,7 @@ def prepare_task_vars(self, task_vars: dict, structured_config_filename: str, *, try: task_vars[var] = self._templar.template(task_vars[var], fail_on_undefined=False) except Exception as e: - raise AnsibleActionFail(f"Exception during templating of task_var '{var}'") from e + raise AnsibleActionFail(f"Exception during templating of task_var '{var}': '{e}'") from e if not isinstance(task_vars, dict): # Corner case for ansible-test where the passed task_vars is a nested chain-map diff --git a/ansible_collections/arista/avd/plugins/filter/deprecated_filters.py b/ansible_collections/arista/avd/plugins/filter/deprecated_filters.py new file mode 100644 index 00000000000..2d587cf139f --- /dev/null +++ b/ansible_collections/arista/avd/plugins/filter/deprecated_filters.py @@ -0,0 +1,47 @@ +# Copyright (c) 2023-2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +# +# deprecated filters - grouped together to avoid Ansible to generate warning on loading the module name... +# + +__metaclass__ = type + +from ansible.errors import AnsibleFilterError + +from ansible_collections.arista.avd.plugins.plugin_utils.pyavd_wrappers import RaiseOnUse, wrap_filter + +PLUGIN_NAME_1 = "arista.avd.generate_lacp_id" +PLUGIN_NAME_2 = "arista.avd.generate_esi" +PLUGIN_NAME_3 = "arista.avd.generate_route_target" + +try: + from pyavd.j2filters import generate_esi, generate_lacp_id, generate_route_target +except ImportError as e: + generate_lacp_id = RaiseOnUse( + AnsibleFilterError( + f"The '{PLUGIN_NAME_1}' plugin requires the 'pyavd' Python library. Got import error", + orig_exc=e, + ) + ) + generate_esi = RaiseOnUse( + AnsibleFilterError( + f"The '{PLUGIN_NAME_2}' plugin requires the 'pyavd' Python library. Got import error", + orig_exc=e, + ) + ) + generate_route_target = RaiseOnUse( + AnsibleFilterError( + f"The '{PLUGIN_NAME_3}' plugin requires the 'pyavd' Python library. Got import error", + orig_exc=e, + ) + ) + + +class FilterModule(object): + def filters(self): + return { + "generate_lacp_id": wrap_filter(PLUGIN_NAME_1)(generate_lacp_id), + "generate_esi": wrap_filter(PLUGIN_NAME_2)(generate_esi), + "generate_route_target": wrap_filter(PLUGIN_NAME_3)(generate_route_target), + } diff --git a/ansible_collections/arista/avd/plugins/filter/generate_esi.py b/ansible_collections/arista/avd/plugins/filter/generate_esi.py deleted file mode 100644 index 4af0b52bfaa..00000000000 --- a/ansible_collections/arista/avd/plugins/filter/generate_esi.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2023-2024 Arista Networks, Inc. -# Use of this source code is governed by the Apache License 2.0 -# that can be found in the LICENSE file. -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.errors import AnsibleFilterError - -from ansible_collections.arista.avd.plugins.plugin_utils.pyavd_wrappers import RaiseOnUse, wrap_filter - -PLUGIN_NAME = "arista.avd.generate_esi" - -try: - from pyavd.j2filters import generate_esi -except ImportError as e: - generate_esi = RaiseOnUse( - AnsibleFilterError( - f"The '{PLUGIN_NAME}' plugin requires the 'pyavd' Python library. Got import error", - orig_exc=e, - ) - ) - - -DOCUMENTATION = r""" ---- -name: generate_esi -collection: arista.avd -author: Arista Ansible Team (@aristanetworks) -version_added: "1.1" -short_description: Transforms short_esi `0303:0202:0101` to EVPN ESI format `0000:0000:0303:0202:0101` -description: Concatenates the given `esi_prefix` and `short_esi`. -positional: _input -options: - _input: - description: Short ESI value as per AVD definition in eos_designs. - type: string - required: true - esi_prefix: - description: ESI prefix value. Will be concatenated with the `short_esi`. - type: string - default: "0000:0000:" -deprecated: - removed_in: "5.0.0" - why: This filter is no longer used by AVD and is very simple to replace with generic Jinja syntax. - alternative: Use Jinja string concatenation instead like `{{ ~ }}` -""" - -EXAMPLES = r""" ---- -esi: "{{ short_esi | arista.avd.generate_esi('deaf:beed:') }}" -""" - -RETURN = r""" ---- -_value: - description: Concatenated string of `esi_prefix` and `short_esi` like `0000:0000:0303:0202:0101` - type: string -""" - - -class FilterModule(object): - def filters(self): - return { - "generate_esi": wrap_filter(PLUGIN_NAME)(generate_esi), - } diff --git a/ansible_collections/arista/avd/plugins/filter/generate_esi.yml b/ansible_collections/arista/avd/plugins/filter/generate_esi.yml new file mode 100644 index 00000000000..f4acbd5508b --- /dev/null +++ b/ansible_collections/arista/avd/plugins/filter/generate_esi.yml @@ -0,0 +1,31 @@ +--- +DOCUMENTATION: + name: generate_esi + collection: arista.avd + author: Arista Ansible Team (@aristanetworks) + version_added: "1.1" + short_description: Transforms short_esi `0303:0202:0101` to EVPN ESI format `0000:0000:0303:0202:0101` + description: Concatenates the given `esi_prefix` and `short_esi`. + positional: _input + options: + _input: + description: Short ESI value as per AVD definition in eos_designs. + type: string + required: true + esi_prefix: + description: ESI prefix value. Will be concatenated with the `short_esi`. + type: string + default: "0000:0000:" + deprecated: + removed_in: "5.0.0" + why: This filter is no longer used by AVD and is very simple to replace with generic Jinja syntax. + alternative: Use Jinja string concatenation instead like `{{ ~ }}` + +EXAMPLES: | + --- + esi: "{{ short_esi | arista.avd.generate_esi('deaf:beed:') }}" + +RETURN: + _value: + description: Concatenated string of `esi_prefix` and `short_esi` like `0000:0000:0303:0202:0101` + type: string diff --git a/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.py b/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.py deleted file mode 100644 index f9e9b507686..00000000000 --- a/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2023-2024 Arista Networks, Inc. -# Use of this source code is governed by the Apache License 2.0 -# that can be found in the LICENSE file. -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.errors import AnsibleFilterError - -from ansible_collections.arista.avd.plugins.plugin_utils.pyavd_wrappers import RaiseOnUse, wrap_filter - -PLUGIN_NAME = "arista.avd.generate_lacp_id" - -try: - from pyavd.j2filters import generate_lacp_id -except ImportError as e: - generate_lacp_id = RaiseOnUse( - AnsibleFilterError( - f"The '{PLUGIN_NAME}' plugin requires the 'pyavd' Python library. Got import error", - orig_exc=e, - ) - ) - -DOCUMENTATION = r""" ---- -name: generate_lacp_id -collection: arista.avd -author: Arista Ansible Team (@aristanetworks) -version_added: "1.1" -short_description: Transforms short_esi `0303:0202:0101` to LACP ID format `0303.0202.0101` -description: Replaces `:` with `.` -positional: _input -options: - _input: - description: Short ESI value as per AVD definition in eos_designs. - type: string - required: true -deprecated: - removed_in: "5.0.0" - why: This filter is no longer used by AVD and is very simple to replace with a generic Jinja filter. - alternative: Use the builtin `replace` filter instead like `{{ | replace(':', '.') }}` -""" - -EXAMPLES = r""" ---- -lacp_id: "{{ short_esi | arista.avd.generate_lacp_id }}" -""" - -RETURN = r""" ---- -_value: - description: String based on LACP ID format like 0303.0202.0101 - type: string -""" - - -class FilterModule(object): - def filters(self): - return { - "generate_lacp_id": wrap_filter(PLUGIN_NAME)(generate_lacp_id), - } diff --git a/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.yml b/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.yml new file mode 100644 index 00000000000..2d19f51297f --- /dev/null +++ b/ansible_collections/arista/avd/plugins/filter/generate_lacp_id.yml @@ -0,0 +1,27 @@ +--- +DOCUMENTATION: + name: generate_lacp_id + collection: arista.avd + author: Arista Ansible Team (@aristanetworks) + version_added: "1.1" + short_description: Transforms short_esi `0303:0202:0101` to LACP ID format `0303.0202.0101` + description: Replaces `:` with `.` + positional: _input + options: + _input: + description: Short ESI value as per AVD definition in eos_designs. + type: string + required: true + deprecated: + removed_in: "5.0.0" + why: This filter is no longer used by AVD and is very simple to replace with a generic Jinja filter. + alternative: Use the builtin `replace` filter instead like `{{ | replace(':', '.') }}` + +EXAMPLES: |- + --- + lacp_id: "{{ short_esi | arista.avd.generate_lacp_id }}" + +RETURN: + _value: + description: String based on LACP ID format like 0303.0202.0101 + type: string diff --git a/ansible_collections/arista/avd/plugins/filter/generate_route_target.py b/ansible_collections/arista/avd/plugins/filter/generate_route_target.py deleted file mode 100644 index 5efa91b9b0d..00000000000 --- a/ansible_collections/arista/avd/plugins/filter/generate_route_target.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2023-2024 Arista Networks, Inc. -# Use of this source code is governed by the Apache License 2.0 -# that can be found in the LICENSE file. -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -from ansible.errors import AnsibleFilterError - -from ansible_collections.arista.avd.plugins.plugin_utils.pyavd_wrappers import RaiseOnUse, wrap_filter - -PLUGIN_NAME = "arista.avd.generate_route_target" - -try: - from pyavd.j2filters import generate_route_target -except ImportError as e: - generate_route_target = RaiseOnUse( - AnsibleFilterError( - f"The '{PLUGIN_NAME}' plugin requires the 'pyavd' Python library. Got import error", - orig_exc=e, - ) - ) - -DOCUMENTATION = r""" ---- -name: generate_route_target -collection: arista.avd -author: Arista Ansible Team (@aristanetworks) -version_added: "1.1" -short_description: Transforms short_esi `0303:0202:0101` to route-target format `03:03:02:02:01:01` -description: Removes `:` and inserts new `:` for each two characters. -positional: _input -options: - _input: - description: Short ESI value as per AVD definition in eos_designs. - type: string - required: true -deprecated: - removed_in: "5.0.0" - why: This filter is no longer used by AVD and is very simple to replace with a generic Jinja filter. - alternative: |- - Use the builtin `ansible.builtin.regex_replace` filter instead like - `{{ | ansible.builtin.regex_replace('(\\d{2})(\\d{2}):(\\d{2})(\\d{2}):(\\d{2})(\\d{2})', '\\1:\\2:\\3:\\4:\\5:\\6') }}` -""" - -EXAMPLES = r""" ---- -rt: "{{ short_esi | arista.avd.generate_route_target }}" -""" - -RETURN = r""" ---- -_value: - description: String based on route-target format like 03:03:02:02:01:01 - type: string -""" - - -class FilterModule(object): - def filters(self): - return { - "generate_route_target": wrap_filter(PLUGIN_NAME)(generate_route_target), - } diff --git a/ansible_collections/arista/avd/plugins/filter/generate_route_target.yml b/ansible_collections/arista/avd/plugins/filter/generate_route_target.yml new file mode 100644 index 00000000000..0dbe48afda9 --- /dev/null +++ b/ansible_collections/arista/avd/plugins/filter/generate_route_target.yml @@ -0,0 +1,29 @@ +--- +DOCUMENTATION: + name: generate_route_target + collection: arista.avd + author: Arista Ansible Team (@aristanetworks) + version_added: "1.1" + short_description: Transforms short_esi `0303:0202:0101` to route-target format `03:03:02:02:01:01` + description: Removes `:` and inserts new `:` for each two characters. + positional: _input + options: + _input: + description: Short ESI value as per AVD definition in eos_designs. + type: string + required: true + deprecated: + removed_in: "5.0.0" + why: This filter is no longer used by AVD and is very simple to replace with a generic Jinja filter. + alternative: |- + Use the builtin `ansible.builtin.regex_replace` filter instead like + `{{ | ansible.builtin.regex_replace('(\\d{2})(\\d{2}):(\\d{2})(\\d{2}):(\\d{2})(\\d{2})', '\\1:\\2:\\3:\\4:\\5:\\6') }}` + +EXAMPLES: |- + --- + rt: "{{ short_esi | arista.avd.generate_route_target }}" + +RETURN: + _value: + description: String based on route-target format like 03:03:02:02:01:01 + type: string diff --git a/ansible_collections/arista/avd/plugins/modules/_emit_warning.py b/ansible_collections/arista/avd/plugins/modules/_emit_warning.py new file mode 100644 index 00000000000..5acc1ab983b --- /dev/null +++ b/ansible_collections/arista/avd/plugins/modules/_emit_warning.py @@ -0,0 +1,28 @@ +# Copyright (c) 2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +DOCUMENTATION = r""" +--- +module: _emit_warning +version_added: "4.9.0" +author: Arista Networks (@aristanetworks) +short_description: Internal module - DO NOT USE - Emit a warning in a task. +description: + - Emit a warning in a task. +options: + message: + description: The warning message to emit. + type: str +""" + +EXAMPLES = r""" +--- +- name: Emit a warning + arista.avd._emit_warning: + message |- + The warning message. + delegate_to: localhost + check_mode: false + run_once: true + changed_when: false +""" diff --git a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/tunnel-interfaces.md b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/tunnel-interfaces.md index 7ddacee8fb2..8001c516a40 100644 --- a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/tunnel-interfaces.md +++ b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/tunnel-interfaces.md @@ -13,6 +13,7 @@ | [    shutdown](## "tunnel_interfaces.[].shutdown") | Boolean | | | | | | [    mtu](## "tunnel_interfaces.[].mtu") | Integer | | | Min: 68
Max: 65535 | | | [    vrf](## "tunnel_interfaces.[].vrf") | String | | | | VRF Name. | + | [    underlay_vrf](## "tunnel_interfaces.[].underlay_vrf") | String | | | | Underlay VRF Name. | | [    ip_address](## "tunnel_interfaces.[].ip_address") | String | | | Format: ipv4_cidr | IPv4_address/Mask. | | [    ipv6_enable](## "tunnel_interfaces.[].ipv6_enable") | Boolean | | | | | | [    ipv6_address](## "tunnel_interfaces.[].ipv6_address") | String | | | Format: ipv6_cidr | IPv6_address/Mask. | @@ -46,6 +47,9 @@ # VRF Name. vrf: + # Underlay VRF Name. + underlay_vrf: + # IPv4_address/Mask. ip_address: ipv6_enable: diff --git a/ansible_collections/arista/avd/roles/eos_validate_state/README.md b/ansible_collections/arista/avd/roles/eos_validate_state/README.md index 8801dd66409..fbf84620aea 100644 --- a/ansible_collections/arista/avd/roles/eos_validate_state/README.md +++ b/ansible_collections/arista/avd/roles/eos_validate_state/README.md @@ -10,6 +10,10 @@ title: Ansible Collection Role eos_validate_state # eos_validate_state +!!! warning + Starting AVD 5.0.0, `eos_validate_state` will use ANTA as backend, which will change the default behavior (same as setting `use_anta: true` in older versions). + Please review the changes described on the [ANTA integration page](./anta_integration.md) + ## Overview **eos_validate_state** is a role leveraged to validate Arista EOS devices' operational states. diff --git a/ansible_collections/arista/avd/roles/eos_validate_state/anta_integration.md b/ansible_collections/arista/avd/roles/eos_validate_state/anta_integration.md index cc48076bafe..b26ebe23ca0 100644 --- a/ansible_collections/arista/avd/roles/eos_validate_state/anta_integration.md +++ b/ansible_collections/arista/avd/roles/eos_validate_state/anta_integration.md @@ -12,6 +12,7 @@ title: Ansible Collection Role eos_validate_state - Integration with ANTA !!! note [ANTA](https://anta.arista.com/stable/) will be the future default framework leveraged by AVD for network testing and validation. Since it introduces small [breaking changes](#breaking-changes), you have to opt-in to leverage ANTA with `eos_validate_state` by configuring: `use_anta: true`. + Starting AVD 5.0.0, `eos_validate_state` will use ANTA as backend, which will change the default behavior (same as setting `use_anta: true` in older versions). # Overview diff --git a/ansible_collections/arista/avd/roles/eos_validate_state/tasks/ansible_tests.yml b/ansible_collections/arista/avd/roles/eos_validate_state/tasks/ansible_tests.yml index 859a261202f..91d56b824ac 100644 --- a/ansible_collections/arista/avd/roles/eos_validate_state/tasks/ansible_tests.yml +++ b/ansible_collections/arista/avd/roles/eos_validate_state/tasks/ansible_tests.yml @@ -5,6 +5,17 @@ ##################################### ## Run ansible eos_validate_state ## ##################################### +- name: "Warning when not using 'use_anta: true'" + arista.avd._emit_warning: + message: |- + Starting AVD 5.0.0, `eos_validate_state` will use ANTA as backend, which will change the default behavior (same as setting `use_anta: true` in older versions). + Please review the changes described on the ANTA integration page on https://avd.arista.com. + delegate_to: localhost + check_mode: false + changed_when: false + run_once: true + tags: + - always - name: Generate variables for testing ansible.builtin.template: diff --git a/ansible_collections/arista/avd/tests/sanity/ignore-2.15.txt b/ansible_collections/arista/avd/tests/sanity/ignore-2.15.txt index 612c268cc12..1deb7156eb1 100644 --- a/ansible_collections/arista/avd/tests/sanity/ignore-2.15.txt +++ b/ansible_collections/arista/avd/tests/sanity/ignore-2.15.txt @@ -12,3 +12,4 @@ plugins/modules/eos_validate_state_runner.py validate-modules:missing-gplv3-lice plugins/modules/eos_validate_state_reports.py validate-modules:missing-gplv3-license plugins/modules/cv_workflow.py validate-modules:missing-gplv3-license plugins/modules/eos_cli_config_gen.py validate-modules:missing-gplv3-license +plugins/modules/_emit_warning.py validate-modules:missing-gplv3-license diff --git a/ansible_collections/arista/avd/tests/sanity/ignore-2.16.txt b/ansible_collections/arista/avd/tests/sanity/ignore-2.16.txt index 612c268cc12..1deb7156eb1 100644 --- a/ansible_collections/arista/avd/tests/sanity/ignore-2.16.txt +++ b/ansible_collections/arista/avd/tests/sanity/ignore-2.16.txt @@ -12,3 +12,4 @@ plugins/modules/eos_validate_state_runner.py validate-modules:missing-gplv3-lice plugins/modules/eos_validate_state_reports.py validate-modules:missing-gplv3-license plugins/modules/cv_workflow.py validate-modules:missing-gplv3-license plugins/modules/eos_cli_config_gen.py validate-modules:missing-gplv3-license +plugins/modules/_emit_warning.py validate-modules:missing-gplv3-license diff --git a/ansible_collections/arista/avd/tests/sanity/ignore-2.17.txt b/ansible_collections/arista/avd/tests/sanity/ignore-2.17.txt index 612c268cc12..1deb7156eb1 100644 --- a/ansible_collections/arista/avd/tests/sanity/ignore-2.17.txt +++ b/ansible_collections/arista/avd/tests/sanity/ignore-2.17.txt @@ -12,3 +12,4 @@ plugins/modules/eos_validate_state_runner.py validate-modules:missing-gplv3-lice plugins/modules/eos_validate_state_reports.py validate-modules:missing-gplv3-license plugins/modules/cv_workflow.py validate-modules:missing-gplv3-license plugins/modules/eos_cli_config_gen.py validate-modules:missing-gplv3-license +plugins/modules/_emit_warning.py validate-modules:missing-gplv3-license diff --git a/mkdocs.yml b/mkdocs.yml index d4311fe483f..52f4a6ca945 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -134,6 +134,7 @@ nav: - Home: index.md - Getting Started: - Introduction to Ansible and AVD: docs/getting-started/intro-to-ansible-and-avd.md + - AVD and Ansible Automation Platform: docs/getting-started/avd-aap.md - Examples: - Single DC L3LS: examples/single-dc-l3ls/README.md - Dual DC L3LS: examples/dual-dc-l3ls/README.md diff --git a/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/tunnel-interfaces.j2 b/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/tunnel-interfaces.j2 index 8a2ca1116a5..46a028933b8 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/tunnel-interfaces.j2 +++ b/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/tunnel-interfaces.j2 @@ -12,8 +12,8 @@ {% set tunnel_interfaces_ipv4 = [] %} {% set tunnel_interfaces_ipv6 = [] %} -| Interface | Description | VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | -| --------- | ----------- | --- | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | +| Interface | Description | VRF | Underlay VRF | MTU | Shutdown | NAT Profile | Mode | Source Interface | Destination | PMTU-Discovery | IPsec Profile | +| --------- | ----------- | --- | ------------ | --- | -------- | ----------- | ---- | ---------------- | ----------- | -------------- | ------------- | {% for tunnel_interface in tunnel_interfaces | arista.avd.natural_sort('name') %} {% if tunnel_interface.ipv6_address is arista.avd.defined %} {% do tunnel_interfaces_ipv6.append(tunnel_interface) %} @@ -23,6 +23,7 @@ {% endif %} {% set description = tunnel_interface.description | arista.avd.default('-') %} {% set vrf = tunnel_interface.vrf | arista.avd.default('default') %} +{% set underlay_vrf = tunnel_interface.underlay_vrf | arista.avd.default('default') %} {% set mtu = tunnel_interface.mtu | arista.avd.default('-') %} {% set shutdown = tunnel_interface.shutdown | arista.avd.default('-') %} {% set nat_profile = tunnel_interface.nat_profile | arista.avd.default('-') %} @@ -31,7 +32,7 @@ {% set row_destination = tunnel_interface.destination | arista.avd.default("-") %} {% set row_pmtu = tunnel_interface.path_mtu_discovery | arista.avd.default("-") %} {% set ipsec_profile = tunnel_interface.ipsec_profile | arista.avd.default("-") %} -| {{ tunnel_interface.name }} | {{ description }} | {{ vrf }} | {{ mtu }} | {{ shutdown }} | {{ nat_profile }} | {{ tunnel_mode }} | {{ row_source_interface }} | {{ row_destination }} | {{ row_pmtu }} | {{ ipsec_profile }} | +| {{ tunnel_interface.name }} | {{ description }} | {{ vrf }} | {{ underlay_vrf }} | {{ mtu }} | {{ shutdown }} | {{ nat_profile }} | {{ tunnel_mode }} | {{ row_source_interface }} | {{ row_destination }} | {{ row_pmtu }} | {{ ipsec_profile }} | {% endfor %} {# IPv4 #} {% if tunnel_interfaces_ipv4 | length > 0 %} diff --git a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/tunnel-interfaces.j2 b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/tunnel-interfaces.j2 index bb41714c046..7bea86ceec6 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/tunnel-interfaces.j2 +++ b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/tunnel-interfaces.j2 @@ -67,6 +67,9 @@ interface {{ tunnel_interface.name }} {% if tunnel_interface.destination is arista.avd.defined %} tunnel destination {{ tunnel_interface.destination }} {% endif %} +{% if tunnel_interface.underlay_vrf is arista.avd.defined %} + tunnel underlay vrf {{ tunnel_interface.underlay_vrf }} +{% endif %} {% if tunnel_interface.path_mtu_discovery is arista.avd.defined(true) %} tunnel path-mtu-discovery {% endif %} diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.jsonschema.json b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.jsonschema.json index 932eeb9519f..cf645f33cf4 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.jsonschema.json +++ b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.jsonschema.json @@ -29548,6 +29548,11 @@ "description": "VRF Name.", "title": "VRF" }, + "underlay_vrf": { + "type": "string", + "description": "Underlay VRF Name.", + "title": "Underlay VRF" + }, "ip_address": { "type": "string", "description": "IPv4_address/Mask.", diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml index ebd64848d37..6b1d7519180 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml +++ b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml @@ -17441,6 +17441,11 @@ keys: description: VRF Name. convert_types: - int + underlay_vrf: + type: str + description: Underlay VRF Name. + convert_types: + - int ip_address: type: str format: ipv4_cidr diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/tunnel_interfaces.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/tunnel_interfaces.schema.yml index 0a38127e456..c1e6a93be63 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/tunnel_interfaces.schema.yml +++ b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/tunnel_interfaces.schema.yml @@ -32,6 +32,11 @@ keys: description: VRF Name. convert_types: - int + underlay_vrf: + type: str + description: Underlay VRF Name. + convert_types: + - int ip_address: type: str format: ipv4_cidr diff --git a/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json b/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json index 0502d419ae2..74e07a4f8c2 100644 --- a/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json +++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json @@ -47456,6 +47456,11 @@ "description": "VRF Name.", "title": "VRF" }, + "underlay_vrf": { + "type": "string", + "description": "Underlay VRF Name.", + "title": "Underlay VRF" + }, "ip_address": { "type": "string", "description": "IPv4_address/Mask.", diff --git a/python-avd/pyavd/_eos_designs/structured_config/network_services/ethernet_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/network_services/ethernet_interfaces.py index 04a7b95635e..ddae52c21a8 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/network_services/ethernet_interfaces.py +++ b/python-avd/pyavd/_eos_designs/structured_config/network_services/ethernet_interfaces.py @@ -33,7 +33,6 @@ def ethernet_interfaces(self: AvdStructuredConfigNetworkServices) -> list | None if not (self.shared_utils.network_services_l3 or self.shared_utils.network_services_l1 or self.shared_utils.l3_interfaces): return None - # Using temp variables to keep the order of interfaces from Jinja ethernet_interfaces = [] subif_parent_interface_names = set()