Skip to content

Commit

Permalink
Refactor(eos_designs): Move documentation to Python (#4364)
Browse files Browse the repository at this point in the history
  • Loading branch information
ClausHolbechArista authored Aug 30, 2024
1 parent b0aff32 commit 20da719
Show file tree
Hide file tree
Showing 46 changed files with 1,138 additions and 536 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ repos:
additional_dependencies: ['deepmerge>=1.1.0', 'PyYAML>=6.0.0', 'pydantic>=2.3.0', 'jsonschema>=4.10.3', 'referencing>=0.35.0']

- id: templates
name: Precompile eos_cli_config_gen Jinja2
name: Precompile Jinja2 templates
entry: sh -c 'python-avd/scripts/compile_templates.py'
language: python
files: python-avd/pyavd/_eos_cli_config_gen/j2templates/
files: python-avd/pyavd/(_eos_cli_config_gen|_eos_designs)/j2templates/
pass_filenames: false
additional_dependencies: ['Jinja2>=3.0.0', 'cryptography>=38.0.4', 'deepmerge>=1.1.0']

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
# This title is used for search results
title: arista.avd.eos_designs_documentation
---
<!--
~ 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.
-->

# eos_designs_documentation

!!! note
Always use the FQCN (Fully Qualified Collection Name) `arista.avd.eos_designs_documentation` when using this plugin.

Generate AVD Fabric Documentation

## Synopsis

The `arista.avd.eos_designs_documentation` module is an Ansible Action Plugin providing the following capabilities:

- Generate fabric documentation using AVD facts and structured configuration files.
- Optionally include connected endpoints documentation.

## Parameters

| Argument | Type | Required | Default | Value Restrictions | Description |
| -------- | ---- | -------- | ------- | ------------------ | ----------- |
| <samp>structured_config_dir</samp> | str | True | None | | Path to directory containing files with AVD structured configurations. |
| <samp>structured_config_suffix</samp> | str | optional | yml | | File suffix for AVD structured configuration files. |
| <samp>fabric_documentation_file</samp> | str | True | None | | Path to output Markdown file. |
| <samp>mode</samp> | str | optional | 0o664 | | Mode of output files. |
| <samp>fabric_documentation</samp> | bool | optional | True | | Generate fabric documentation. |
| <samp>include_connected_endpoints</samp> | bool | optional | False | | Include connected endpoints in fabric documentation. |
| <samp>topology_csv_file</samp> | str | True | None | | Path to output topology CSV file. |
| <samp>topology_csv</samp> | bool | optional | False | | Generate Topology CSV with all interfaces towards other devices. |
| <samp>p2p_links_csv_file</samp> | str | True | None | | Path to output P2P links CSV file. |
| <samp>p2p_links_csv</samp> | bool | optional | False | | Generate P2P links CSV with all routed point-to-point links between devices. |

## Examples

```yaml
---

- name: Generate fabric documentation
tags: [build, provision, documentation]
arista.avd.eos_designs_documentation:
structured_config_dir: "{{ structured_dir }}"
structured_config_suffix: "{{ avd_structured_config_file_format }}"
fabric_documentation_file: "{{ fabric_dir }}/{{ fabric_name }}-documentation.md"
fabric_documentation: "{{ eos_designs_documentation.enabled | arista.avd.default(true) }}"
include_connected_endpoints: "{{ eos_designs_documentation.connected_endpoints | arista.avd.default(false) }}"
topology_csv_file: "{{ fabric_dir }}/{{ fabric_name }}-topology.csv"
topology_csv: "{{ eos_designs_documentation.topology_csv | arista.avd.default(true) }}"
p2p_links_csv_file: "{{ fabric_dir }}/{{ fabric_name }}-topology.csv"
p2p_links_csv: "{{ eos_designs_documentation.p2p_links_csv | arista.avd.default(true) }}"
mode: "0o664"
delegate_to: localhost
check_mode: false
run_once: true
```
## Authors
- Arista Ansible Team (@aristanetworks)
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |

### VTEP Loopback Node allocation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 10.255.1.0/27 | 32 | 4 | 12.5 % |
| 10.255.129.0/27 | 32 | 4 | 12.5 % |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |

### VTEP Loopback Node allocation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |

### VTEP Loopback Node allocation

Expand All @@ -94,7 +94,6 @@
| Key | Type | Description |
| --- | ---- | ----------- |
| firewalls | firewall | - |
| routers | router | - |
| servers | server | - |

### Firewalls
Expand All @@ -117,8 +116,8 @@

| Profile Name | Parent Profile |
| ------------ | -------------- |
| PP-DEFAULTS | - |
| PP-BLUE | PP-DEFAULTS |
| PP-DEFAULTS | - |
| PP-FIREWALL | - |
| PP-GREEN | PP-DEFAULTS |
| PP-ORANGE | PP-DEFAULTS |
| PP-FIREWALL | - |
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 10.255.1.0/27 | 32 | 4 | 12.5 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 192.168.254.0/24 | 256 | 7 | 2.74 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |

### VTEP Loopback Node allocation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |

### VTEP Loopback Node allocation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 172.18.110.0/24 | 256 | 3 | 1.18 % |
| 172.18.120.0/24 | 256 | 1 | 0.4 % |
| 172.18.210.0/24 | 256 | 2 | 0.79 % |
Expand All @@ -245,31 +245,20 @@

| Key | Type | Description |
| --- | ---- | ----------- |
| access_points | access_point | Access Point |
| cameras | camera | Camera |
| cpes | cpe | CPE |
| firewalls | firewall | Firewall |
| generic_devices | generic_device | Generic Device |
| load_balancers | load_balancer | Load Balancer |
| phones | phone | Phone |
| printers | printer | Printer |
| routers | router | Router |
| servers | server | Server |
| storage_arrays | storage_array | Storage Array |
| workstations | workstation | Workstation |

### Servers

| Name | Port | Fabric Device | Fabric Port | Description | Shutdown | Type | Mode | VLANs | Profile |
| ---- | ---- | ------------- | ------------| ----------- | -------- | ---- | ---- | ----- | ------- |
| server-1 | Eth2 | DC1-POD1-LEAF2B | Ethernet16 | server-1_Eth2 | False | switched | access | 110 | TENANT_A |
| server-1 | Eth4 | DC1-POD1-LEAF2B | Ethernet17 | Set using structured_config on server adapter | False | switched | access | 110 | TENANT_A |
| server-1 | Eth6 | DC1-POD1-LEAF2B | Ethernet18 | server-1_Eth6 | False | switched | access | 110 | NESTED_TENANT_A |
| server-1 | Eth8 | DC1-POD1-LEAF2B | Ethernet19 | server-1_Eth8 | False | switched | access | 110 | NESTED_TENANT_A |
| server-1 | Eth1 | DC1.POD1.LEAF2A | Ethernet16 | server-1_Eth1 | False | switched | access | 110 | TENANT_A |
| server-1 | Eth3 | DC1.POD1.LEAF2A | Ethernet17 | Set using structured_config on server adapter | False | switched | access | 110 | TENANT_A |
| server-1 | Eth5 | DC1.POD1.LEAF2A | Ethernet18 | server-1_Eth5 | False | switched | access | 110 | NESTED_TENANT_A |
| server-1 | Eth7 | DC1.POD1.LEAF2A | Ethernet19 | server-1_Eth7 | False | switched | access | 110 | NESTED_TENANT_A |
| server-1 | Eth2 | DC1-POD1-LEAF2B | Ethernet16 | server-1_Eth2 | False | switched | access | 110 | TENANT_A |
| server-1 | Eth4 | DC1-POD1-LEAF2B | Ethernet17 | Set using structured_config on server adapter | False | switched | access | 110 | TENANT_A |
| server-1 | Eth6 | DC1-POD1-LEAF2B | Ethernet18 | server-1_Eth6 | False | switched | access | 110 | NESTED_TENANT_A |
| server-1 | Eth8 | DC1-POD1-LEAF2B | Ethernet19 | server-1_Eth8 | False | switched | access | 110 | NESTED_TENANT_A |

### Port Profiles

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 192.168.254.0/24 | 256 | 4 | 1.57 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 192.168.254.0/24 | 256 | 4 | 1.57 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 192.168.254.0/24 | 256 | 7 | 2.74 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
### VTEP Loopback VXLAN Tunnel Source Interfaces (VTEPs Only)

| VTEP Loopback Pool | Available Addresses | Assigned addresses | Assigned Address % |
| --------------------- | ------------------- | ------------------ | ------------------ |
| ------------------ | ------------------- | ------------------ | ------------------ |
| 192.168.254.0/24 | 256 | 11 | 4.3 % |

### VTEP Loopback Node allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ def run(self, tmp: Any = None, task_vars: dict | None = None) -> dict:
setup_module_logging(result)

# Get task arguments and validate them
validated_args = strip_empties_from_dict(self._task.args)
validation_result, validated_args = self.validate_argument_spec(ARGUMENT_SPEC)
validated_args = strip_empties_from_dict(validated_args)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# 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.
import json
import logging
from pathlib import Path
from typing import Any

from ansible.errors import AnsibleActionFail
from ansible.plugins.action import ActionBase, display
from yaml import load

from ansible_collections.arista.avd.plugins.plugin_utils.utils import PythonToAnsibleHandler, YamlLoader, write_file

try:
from pyavd._utils import get, strip_empties_from_dict
from pyavd.get_fabric_documentation import get_fabric_documentation

HAS_PYAVD = True
except ImportError:
HAS_PYAVD = False


LOGGER = logging.getLogger("ansible_collections.arista.avd")
LOGGING_LEVELS = ["DEBUG", "INFO", "ERROR", "WARNING", "CRITICAL"]

ARGUMENT_SPEC = {
"structured_config_dir": {"type": "str", "required": True},
"structured_config_suffix": {"type": "str", "default": "yml"},
"fabric_documentation_file": {"type": "str", "required": True},
"mode": {"type": "str", "default": "0o664"},
"fabric_documentation": {"type": "bool", "default": True},
"include_connected_endpoints": {"type": "bool", "default": False},
"topology_csv_file": {"type": "str", "required": True},
"topology_csv": {"type": "bool", "default": False},
"p2p_links_csv_file": {"type": "str", "required": True},
"p2p_links_csv": {"type": "bool", "default": False},
}


class ActionModule(ActionBase):
def run(self, tmp: Any = None, task_vars: dict | None = None) -> None:
self._supports_check_mode = False

if task_vars is None:
task_vars = {}

result = super().run(tmp, task_vars)
del tmp # tmp no longer has any effect

if not HAS_PYAVD:
msg = "The arista.avd.eos_designs_documentation' plugin requires the 'pyavd' Python library. Got import error"
raise AnsibleActionFail(msg)

# Setup module logging
setup_module_logging(result)

# Get task arguments and validate them
validation_result, validated_args = self.validate_argument_spec(ARGUMENT_SPEC)
validated_args = strip_empties_from_dict(validated_args)

# Converting to json and back to remove any AnsibeUnsafe types
validated_args = json.loads(json.dumps(validated_args))

return self.main(validated_args, task_vars, result)

def main(self, validated_args: dict, task_vars: dict, result: dict) -> dict:
avd_switch_facts: dict = get(task_vars, "avd_switch_facts", required=True)
device_list = list(avd_switch_facts.keys())

structured_configs = self.read_structured_configs(
device_list=device_list,
structured_config_dir=validated_args["structured_config_dir"],
structured_config_suffix=validated_args["structured_config_suffix"],
)
fabric_name = get(task_vars, "fabric_name", required=True)
output = get_fabric_documentation(
{"avd_switch_facts": avd_switch_facts},
structured_configs=structured_configs,
fabric_name=fabric_name,
fabric_documentation=validated_args["fabric_documentation"],
include_connected_endpoints=validated_args["include_connected_endpoints"],
topology_csv=validated_args["topology_csv"],
p2p_links_csv=validated_args["p2p_links_csv"],
)
if output.fabric_documentation:
result["changed"] = write_file(
content=output.fabric_documentation,
filename=validated_args["fabric_documentation_file"],
file_mode=validated_args["mode"],
)
if output.topology_csv:
changed = write_file(
content=output.topology_csv,
filename=validated_args["topology_csv_file"],
file_mode=validated_args["mode"],
)
result["changed"] = result.get("changed") or changed

if output.p2p_links_csv:
changed = write_file(
content=output.p2p_links_csv,
filename=validated_args["p2p_links_csv_file"],
file_mode=validated_args["mode"],
)
result["changed"] = result.get("changed") or changed

return result

def read_structured_configs(self, device_list: list[str], structured_config_dir: str, structured_config_suffix: str) -> dict[str, dict]:
return {device: self.read_one_structured_config(device, structured_config_dir, structured_config_suffix) for device in device_list}

def read_one_structured_config(self, device: str, structured_config_dir: str, structured_config_suffix: str) -> dict:
path = Path(structured_config_dir, f"{device}.{structured_config_suffix}")
if not path.exists():
logging.warning("Could not find structured config file for '%s'. The documentation may be incomplete.", device)

with path.open(encoding="UTF-8") as stream:
if structured_config_suffix in ["yml", "yaml"]:
return load(stream, Loader=YamlLoader) # noqa: S506

# JSON
return json.load(stream)


def setup_module_logging(result: dict) -> None:
"""
Add a Handler to copy the logs from the plugin into Ansible output based on their level.
Parameters:
result: The dictionary used for the ansible module results
"""
python_to_ansible_handler = PythonToAnsibleHandler(result, display)
LOGGER.addHandler(python_to_ansible_handler)
# TODO: mechanism to manipulate the logger globally for pyavd
# Keep debug to be able to see logs with `-v` and `-vvv`
LOGGER.setLevel(logging.DEBUG)
Loading

0 comments on commit 20da719

Please sign in to comment.