diff --git a/ansible_collections/arista/avd/plugins/action/eos_designs_facts.py b/ansible_collections/arista/avd/plugins/action/eos_designs_facts.py
index 88e4bdbde85..f11bfc2f9e4 100644
--- a/ansible_collections/arista/avd/plugins/action/eos_designs_facts.py
+++ b/ansible_collections/arista/avd/plugins/action/eos_designs_facts.py
@@ -144,15 +144,6 @@ def create_avd_switch_facts_instances(self, fabric_hosts: list, hostvars: object
# Fetch all templated Ansible vars for this host
host_hostvars = dict(hostvars.get(host))
- # Initialize SharedUtils class to be passed to EosDesignsFacts below.
- shared_utils = SharedUtils(hostvars=host_hostvars, templar=self.templar, schema=avdschematools.avdschema)
-
- # Insert dynamic keys into the input data if not set.
- # These keys are required by the schema, but the default values are set inside shared_utils.
- host_hostvars.setdefault("node_type_keys", shared_utils.node_type_keys)
- host_hostvars.setdefault("connected_endpoints_keys", shared_utils.connected_endpoints_keys)
- host_hostvars.setdefault("network_services_keys", shared_utils.network_services_keys)
-
# Set correct hostname in schema tools and perform conversion and validation
avdschematools.hostname = host
host_result = avdschematools.convert_and_validate_data(host_hostvars, return_counters=True)
@@ -168,6 +159,9 @@ def create_avd_switch_facts_instances(self, fabric_hosts: list, hostvars: object
# This is used to access EosDesignsFacts objects of other switches during rendering of one switch.
host_hostvars["avd_switch_facts"] = avd_switch_facts
+ # Initialize SharedUtils class to be passed to EosDesignsFacts below.
+ shared_utils = SharedUtils(hostvars=host_hostvars, templar=self.templar, schema=avdschematools.avdschema)
+
# Create an instance of EosDesignsFacts and insert into common avd_switch_facts dict
avd_switch_facts[host] = {"switch": EosDesignsFacts(hostvars=host_hostvars, shared_utils=shared_utils)}
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
index 00ce398cda7..586c49e88f6 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
@@ -7,7 +7,7 @@
| Variable | Type | Required | Default | Value Restrictions | Description |
| -------- | ---- | -------- | ------- | ------------------ | ----------- |
- | [<connected_endpoints_keys.key>](## "") | List, items: Dictionary | | See (+) on YAML tab | | This should be applied to group_vars or host_vars where endpoints are connecting.
`connected_endpoints_keys.key` is one of the keys under "connected_endpoints_keys".
The default keys are `servers`, `firewalls`, `routers`, `load_balancers`, and `storage_arrays`.
|
+ | [<connected_endpoints_keys.key>](## "") | List, items: Dictionary | | | | This should be applied to group_vars or host_vars where endpoints are connecting.
`connected_endpoints_keys.key` is one of the keys under "connected_endpoints_keys".
|
| [ - name](## ".[].name") | String | Required, Unique | | | Endpoint name will be used in the switchport description. |
| [ rack](## ".[].rack") | String | | | | Rack is used for documentation purposes only. |
| [ adapters](## ".[].adapters") | List, items: Dictionary | | | | A list of adapters, group by adapters leveraging the same port-profile. |
@@ -165,8 +165,7 @@
```yaml
# This should be applied to group_vars or host_vars where endpoints are connecting.
# `connected_endpoints_keys.key` is one of the keys under "connected_endpoints_keys".
- # The default keys are `servers`, `firewalls`, `routers`, `load_balancers`, and `storage_arrays`.
- : # (1)!
+ :
# Endpoint name will be used in the switchport description.
- name:
@@ -551,45 +550,3 @@
# Custom structured config added under ethernet_interfaces.[name=] for eos_cli_config_gen.
structured_config:
```
-
- 1. Default Value
-
- ```yaml
- :
- - description: Server
- key: servers
- type: server
- - description: Firewall
- key: firewalls
- type: firewall
- - description: Router
- key: routers
- type: router
- - description: Load Balancer
- key: load_balancers
- type: load_balancer
- - description: Storage Array
- key: storage_arrays
- type: storage_array
- - description: CPE
- key: cpes
- type: cpe
- - description: Workstation
- key: workstations
- type: workstation
- - description: Access Point
- key: access_points
- type: access_point
- - description: Phone
- key: phones
- type: phone
- - description: Printer
- key: printers
- type: printer
- - description: Camera
- key: cameras
- type: camera
- - description: Generic Device
- key: generic_devices
- type: generic_device
- ```
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/custom-node-type-keys.key.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/custom-node-type-keys.key.md
new file mode 100644
index 00000000000..168389787e8
--- /dev/null
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/custom-node-type-keys.key.md
@@ -0,0 +1,16 @@
+
+=== "Table"
+
+ | Variable | Type | Required | Default | Value Restrictions | Description |
+ | -------- | ---- | -------- | ------- | ------------------ | ----------- |
+ | [<custom_node_type_keys.key>](## "") | Dictionary | | | | |
+
+=== "YAML"
+
+ ```yaml
+ :
+ ```
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/type-setting.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/type-setting.md
index ce8e58d01b8..f9c422de72e 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/type-setting.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/type-setting.md
@@ -7,12 +7,12 @@
| Variable | Type | Required | Default | Value Restrictions | Description |
| -------- | ---- | -------- | ------- | ------------------ | ----------- |
- | [type](## "type") | String | | | Valid Values:
-
| The `type:` variable needs to be defined for each device in the fabric.
This is leveraged to load the appropriate template to generate the configuration.
|
+ | [type](## "type") | String | | | Valid Values:
-
-
| The `type:` variable needs to be defined for each device in the fabric.
This is leveraged to load the appropriate template to generate the configuration.
|
=== "YAML"
```yaml
# The `type:` variable needs to be defined for each device in the fabric.
# This is leveraged to load the appropriate template to generate the configuration.
- type: ">
+ type: " | "">
```
diff --git a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
index 6119aca588d..35581fddd55 100644
--- a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
@@ -3922,7 +3922,9 @@ keys:
documentation_options:
table: type-setting
type: str
- dynamic_valid_values: node_type_keys.type
+ dynamic_valid_values:
+ - custom_node_type_keys.type
+ - node_type_keys.type
description: 'The `type:` variable needs to be defined for each device in the
fabric.
@@ -4737,43 +4739,11 @@ dynamic_keys:
display_name: Connected Endpoints
documentation_options:
table: connected-endpoints
- default:
- - key: servers
- type: server
- description: Server
- - key: firewalls
- type: firewall
- description: Firewall
- - key: routers
- type: router
- description: Router
- - key: load_balancers
- type: load_balancer
- description: Load Balancer
- - key: storage_arrays
- type: storage_array
- description: Storage Array
- - key: cpes
- type: cpe
- description: CPE
- - key: workstations
- type: workstation
- description: Workstation
- - key: access_points
- type: access_point
- description: Access Point
- - key: phones
- type: phone
- description: Phone
- - key: printers
- type: printer
- description: Printer
- - key: cameras
- type: camera
- description: Camera
- - key: generic_devices
- type: generic_device
- description: Generic Device
+ custom_node_type_keys.key:
+ $ref: eos_designs#/$defs/node_type
+ type: dict
+ documentation_options:
+ hide_keys: true
network_services_keys.name:
$ref: eos_designs#/$defs/network_services
type: list
@@ -5447,9 +5417,6 @@ $defs:
`connected_endpoints_keys.key` is one of the keys under "connected_endpoints_keys".
- The default keys are `servers`, `firewalls`, `routers`, `load_balancers`, and
- `storage_arrays`.
-
'
items:
type: dict
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/connected_endpoints.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/connected_endpoints.schema.yml
index 5165b7553da..8439934367c 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/connected_endpoints.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/connected_endpoints.schema.yml
@@ -12,42 +12,3 @@ dynamic_keys:
display_name: Connected Endpoints
documentation_options:
table: connected-endpoints
- default:
- # NOTE: there is a static list of default endpoint keys in the
- # fabric connected endpoints documentation templates.
- - key: servers
- type: server
- description: Server
- - key: firewalls
- type: firewall
- description: Firewall
- - key: routers
- type: router
- description: Router
- - key: load_balancers
- type: load_balancer
- description: Load Balancer
- - key: storage_arrays
- type: storage_array
- description: Storage Array
- - key: cpes
- type: cpe
- description: CPE
- - key: workstations
- type: workstation
- description: Workstation
- - key: access_points
- type: access_point
- description: Access Point
- - key: phones
- type: phone
- description: Phone
- - key: printers
- type: printer
- description: Printer
- - key: cameras
- type: camera
- description: Camera
- - key: generic_devices
- type: generic_device
- description: Generic Device
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/custom_node_type.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/custom_node_type.schema.yml
new file mode 100644
index 00000000000..129134c7030
--- /dev/null
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/custom_node_type.schema.yml
@@ -0,0 +1,13 @@
+# 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.
+# yaml-language-server: $schema=../../../_schema/avd_meta_schema.json
+# Line above is used by RedHat's YAML Schema vscode extension
+# Use Ctrl + Space to get suggestions for every field. Autocomplete will pop up after typing 2 letters.
+type: dict
+dynamic_keys:
+ "custom_node_type_keys.key":
+ $ref: "eos_designs#/$defs/node_type"
+ type: dict
+ documentation_options:
+ hide_keys: true
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_connected_endpoints.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_connected_endpoints.schema.yml
index d11ed699eff..20b56cbf481 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_connected_endpoints.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_connected_endpoints.schema.yml
@@ -12,7 +12,6 @@ $defs:
description: |
This should be applied to group_vars or host_vars where endpoints are connecting.
`connected_endpoints_keys.key` is one of the keys under "connected_endpoints_keys".
- The default keys are `servers`, `firewalls`, `routers`, `load_balancers`, and `storage_arrays`.
items:
type: dict
keys:
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/type.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/type.schema.yml
index 137bac6937b..bb52e0fb44e 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/type.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/type.schema.yml
@@ -10,7 +10,9 @@ keys:
documentation_options:
table: type-setting
type: str
- dynamic_valid_values: "node_type_keys.type"
+ dynamic_valid_values:
+ - custom_node_type_keys.type
+ - node_type_keys.type
description: |
The `type:` variable needs to be defined for each device in the fabric.
This is leveraged to load the appropriate template to generate the configuration.
diff --git a/python-avd/pyavd/_eos_designs/structured_config/__init__.py b/python-avd/pyavd/_eos_designs/structured_config/__init__.py
index f804d5a88c5..c29309a4359 100644
--- a/python-avd/pyavd/_eos_designs/structured_config/__init__.py
+++ b/python-avd/pyavd/_eos_designs/structured_config/__init__.py
@@ -78,21 +78,6 @@ def get_structured_config(
Returns:
The structured_config as a dict
"""
- structured_config = {}
- module_vars = ChainMap(
- structured_config,
- vars,
- )
-
- # Initialize SharedUtils class to be passed to each python_module below.
- shared_utils = SharedUtils(hostvars=module_vars, templar=templar, schema=input_schema_tools.avdschema)
-
- # Insert dynamic keys into the input data if not set.
- # These keys are required by the schema, but the default values are set inside shared_utils.
- vars.setdefault("node_type_keys", shared_utils.node_type_keys)
- vars.setdefault("connected_endpoints_keys", shared_utils.connected_endpoints_keys)
- vars.setdefault("network_services_keys", shared_utils.network_services_keys)
-
# Validate input data
if validate:
result.update(input_schema_tools.convert_and_validate_data(vars))
@@ -100,6 +85,12 @@ def get_structured_config(
# Input data validation failed so return empty dict. Calling function should check result.get("failed").
return {}
+ structured_config = {}
+ module_vars = ChainMap(structured_config, vars)
+
+ # Initialize SharedUtils class to be passed to each python_module below.
+ shared_utils = SharedUtils(hostvars=module_vars, templar=templar, schema=input_schema_tools.avdschema)
+
for cls in AVD_STRUCTURED_CONFIG_CLASSES:
eos_designs_module: AvdFacts = cls(module_vars, shared_utils)
results = eos_designs_module.render()
diff --git a/python-avd/pyavd/_schema/avd_meta_schema.json b/python-avd/pyavd/_schema/avd_meta_schema.json
index 2ec84057ecf..bc97a16186d 100644
--- a/python-avd/pyavd/_schema/avd_meta_schema.json
+++ b/python-avd/pyavd/_schema/avd_meta_schema.json
@@ -376,8 +376,11 @@
"description": "Key is required"
},
"dynamic_valid_values": {
- "type": "string",
- "description": "Path to variable under the parent dictionary containing valid values.\nVariable path use dot-notation and variable path must be relative to the parent dictionary.\nIf an element of the variable path is a list, every list item will be unpacked.\nNote that this is building the schema from values in the _data_ being validated!"
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "Path to variable under the parent dictionary containing valid values.\nVariable path use dot-notation and variable path must be relative to the parent dictionary.\nIf an element of the variable path is a list, every list item will be unpacked.\nNote that this is building the schema from values in the _data_ being validated!"
+ }
},
"$ref": {
"type": "string",
diff --git a/python-avd/pyavd/_schema/avddataconverter.py b/python-avd/pyavd/_schema/avddataconverter.py
index c3adeef9a8b..1410361f649 100644
--- a/python-avd/pyavd/_schema/avddataconverter.py
+++ b/python-avd/pyavd/_schema/avddataconverter.py
@@ -8,6 +8,8 @@
from pyavd._errors import AvdDeprecationWarning
from pyavd._utils import get_all
+from .utils import get_instance_with_defaults
+
SCHEMA_TO_PY_TYPE_MAP = {
"str": str,
"int": int,
@@ -92,7 +94,8 @@ def convert_dynamic_keys(self, dynamic_keys: dict, data: dict, schema: dict, pat
# Resolve "keys" from schema "dynamic_keys" by looking for the dynamic key in data.
keys = {}
for dynamic_key, childschema in dynamic_keys.items():
- resolved_keys = get_all(data, dynamic_key)
+ data_with_defaults = get_instance_with_defaults(data, dynamic_key, schema)
+ resolved_keys = get_all(data_with_defaults, dynamic_key)
for resolved_key in resolved_keys:
keys.setdefault(resolved_key, childschema)
diff --git a/python-avd/pyavd/_schema/avdvalidator.py b/python-avd/pyavd/_schema/avdvalidator.py
index bb984995caa..8456fcaccb7 100644
--- a/python-avd/pyavd/_schema/avdvalidator.py
+++ b/python-avd/pyavd/_schema/avdvalidator.py
@@ -9,6 +9,8 @@
from pyavd._errors import AvdValidationError
from pyavd._utils import get_all, get_all_with_path, get_indices_of_duplicate_items
+from .utils import get_instance_with_defaults
+
class AvdValidator:
def __init__(self, schema: dict) -> None:
@@ -109,7 +111,8 @@ def keys_validator(self, keys: dict, instance: dict, schema: dict, path: list[st
schema_dynamic_keys = schema.get("dynamic_keys", {})
dynamic_keys = {}
for dynamic_key, childschema in schema_dynamic_keys.items():
- resolved_keys = get_all(instance, dynamic_key)
+ instance_with_defaults = get_instance_with_defaults(instance, dynamic_key, schema)
+ resolved_keys = get_all(instance_with_defaults, dynamic_key)
for resolved_key in resolved_keys:
dynamic_keys.setdefault(resolved_key, childschema)
@@ -124,7 +127,8 @@ def keys_validator(self, keys: dict, instance: dict, schema: dict, path: list[st
# Run over child keys and check for required and update child schema with dynamic valid values before
# descending into validation of child schema.
- for key, childschema in all_keys.items():
+ for key in all_keys:
+ childschema = all_keys[key].copy()
if instance.get(key) is None:
# Validation of "required" on child keys
if childschema.get("required"):
@@ -135,7 +139,9 @@ def keys_validator(self, keys: dict, instance: dict, schema: dict, path: list[st
# Expand "dynamic_valid_values" in child schema and add to "valid_values"
if "dynamic_valid_values" in childschema:
- childschema.setdefault("valid_values", []).extend(get_all(instance, childschema["dynamic_valid_values"]))
+ for dynamic_valid_value in childschema["dynamic_valid_values"]:
+ instance_with_defaults = get_instance_with_defaults(instance, dynamic_valid_value, schema)
+ childschema.setdefault("valid_values", []).extend(get_all(instance_with_defaults, dynamic_valid_value))
# Perform regular validation of the child schema.
yield from self.validate(
diff --git a/python-avd/pyavd/_schema/utils.py b/python-avd/pyavd/_schema/utils.py
new file mode 100644
index 00000000000..418296d3b45
--- /dev/null
+++ b/python-avd/pyavd/_schema/utils.py
@@ -0,0 +1,29 @@
+# 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.
+from collections import ChainMap
+
+from pyavd._utils import get
+
+
+def get_instance_with_defaults(instance: dict, dynamic_key_path: str, schema: dict) -> dict | ChainMap:
+ """
+ Returns the instance including any default value of the given dynamic key path.
+
+ If the dynamic key path is already in the instance, the instance is returned as-is.
+ """
+ dynamic_root_key = dynamic_key_path.split(".", maxsplit=1)[0]
+
+ if dynamic_root_key in instance:
+ # The key is already set, so no need to find the default value.
+ return instance
+
+ if dynamic_root_key == "node_type_keys":
+ # TODO: AVD6.0.0 remove this if block when we remove the reliance on design.type.
+ from pyavd._eos_designs.shared_utils.node_type_keys import DEFAULT_NODE_TYPE_KEYS
+
+ design_type = get(instance, "design.type", default="l3ls-evpn")
+ return ChainMap(instance, {"node_type_keys": DEFAULT_NODE_TYPE_KEYS[design_type]})
+
+ # Fetch default value from schema
+ return ChainMap(instance, {dynamic_root_key: get(schema, f"keys.{dynamic_root_key}.default")})
diff --git a/python-avd/pyavd/_utils/get_all.py b/python-avd/pyavd/_utils/get_all.py
index 3cc85dd7d55..ec9eb438359 100644
--- a/python-avd/pyavd/_utils/get_all.py
+++ b/python-avd/pyavd/_utils/get_all.py
@@ -3,6 +3,7 @@
# that can be found in the LICENSE file.
from __future__ import annotations
+from collections import ChainMap
from typing import TYPE_CHECKING, Any
from pyavd._errors import AristaAvdMissingVariableError
@@ -50,7 +51,7 @@ def get_all(data: Any, path: str, required: bool = False, org_path: str | None =
return output
- if isinstance(data, dict):
+ if isinstance(data, (dict, ChainMap)):
value = data.get(path_elements[0])
if value is None:
@@ -96,7 +97,7 @@ def get_all_with_path(data: Any, path: str, _current_path: list[str | int] | Non
for index, data_item in enumerate(data):
yield from get_all_with_path(data_item, path, _current_path=[*_current_path, index])
- elif isinstance(data, dict):
+ elif isinstance(data, (dict, ChainMap)):
value = data.get(path_elements[0])
if value is None:
diff --git a/python-avd/pyavd/validate_inputs.py b/python-avd/pyavd/validate_inputs.py
index 783437df50c..0c8bf3ba14a 100644
--- a/python-avd/pyavd/validate_inputs.py
+++ b/python-avd/pyavd/validate_inputs.py
@@ -22,20 +22,11 @@ def validate_inputs(inputs: dict) -> ValidationResult:
Validation result object with any validation errors or deprecation warnings.
"""
# pylint: disable=import-outside-toplevel
- from ._eos_designs.shared_utils import SharedUtils
from .avd_schema_tools import EosDesignsAvdSchemaTools
# pylint: enable=import-outside-toplevel
eos_designs_schema_tools = EosDesignsAvdSchemaTools()
- # Initialize SharedUtils class to fetch default variables below.
- shared_utils = SharedUtils(hostvars=inputs, templar=None, schema=eos_designs_schema_tools.avdschema)
-
- # Insert dynamic keys into the input data if not set.
- # These keys are required by the schema, but the default values are set inside shared_utils.
- inputs.setdefault("node_type_keys", shared_utils.node_type_keys)
- inputs.setdefault("connected_endpoints_keys", shared_utils.connected_endpoints_keys)
- inputs.setdefault("network_services_keys", shared_utils.network_services_keys)
# Inplace conversion of data
deprecation_warnings = eos_designs_schema_tools.convert_data(inputs)
diff --git a/python-avd/schema_tools/generate_docs/tablerowgen.py b/python-avd/schema_tools/generate_docs/tablerowgen.py
index a94df9d4a9a..c43c0c02f6a 100644
--- a/python-avd/schema_tools/generate_docs/tablerowgen.py
+++ b/python-avd/schema_tools/generate_docs/tablerowgen.py
@@ -210,7 +210,7 @@ def get_restrictions(self) -> list:
restrictions = []
valid_values = []
if getattr(self.schema, "dynamic_valid_values", None):
- valid_values.append(f"")
+ valid_values.extend(f"" for dynamic_valid_value in self.schema.dynamic_valid_values)
if getattr(self.schema, "valid_values", None):
valid_values.extend(self.schema.valid_values)
diff --git a/python-avd/schema_tools/generate_docs/yamllinegen.py b/python-avd/schema_tools/generate_docs/yamllinegen.py
index affe12ff446..45d3c7f2b4a 100644
--- a/python-avd/schema_tools/generate_docs/yamllinegen.py
+++ b/python-avd/schema_tools/generate_docs/yamllinegen.py
@@ -217,7 +217,7 @@ def get_restrictions(self) -> list:
restrictions = []
valid_values = []
if getattr(self.schema, "dynamic_valid_values", None):
- valid_values.append(f"")
+ valid_values.extend(f"" for dynamic_valid_value in self.schema.dynamic_valid_values)
if getattr(self.schema, "valid_values", None):
valid_values.extend(self.schema.valid_values)
diff --git a/python-avd/schema_tools/metaschema/meta_schema_model.py b/python-avd/schema_tools/metaschema/meta_schema_model.py
index 8fd52221adf..8f625c2426d 100644
--- a/python-avd/schema_tools/metaschema/meta_schema_model.py
+++ b/python-avd/schema_tools/metaschema/meta_schema_model.py
@@ -242,9 +242,9 @@ class ConvertType(str, Enum):
"""Maximum value"""
valid_values: list[int] | None = None
"""List of valid values"""
- dynamic_valid_values: str | None = None
+ dynamic_valid_values: list[str] | None = None
"""
- Path to variable under the parent dictionary containing valid values.
+ List of path to variable under the parent dictionary containing valid values.
Variable path use dot-notation and variable path must be relative to the parent dictionary.
If an element of the variable path is a list, every list item will be unpacked.
Note that this is building the schema from values in the _data_ being validated!
@@ -277,9 +277,9 @@ class ConvertType(str, Enum):
"""Default value"""
valid_values: list[bool] | None = None
"""List of valid values"""
- dynamic_valid_values: str | None = None
+ dynamic_valid_values: list[str] | None = None
"""
- Path to variable under the parent dictionary containing valid values.
+ List of paths to variable under the parent dictionary containing valid values.
Variable path use dot-notation and variable path must be relative to the parent dictionary.
If an element of the variable path is a list, every list item will be unpacked.
Note that this is building the schema from values in the _data_ being validated!
@@ -339,9 +339,9 @@ def __str__(self) -> str:
"""
valid_values: list[str] | None = None
"""List of valid values"""
- dynamic_valid_values: str | None = None
+ dynamic_valid_values: list[str] | None = None
"""
- Path to variable under the parent dictionary containing valid values.
+ List of paths to variable under the parent dictionary containing valid values.
Variable path use dot-notation and variable path must be relative to the parent dictionary.
If an element of the variable path is a list, every list item will be unpacked.
Note that this is building the schema from values in the _data_ being validated!
diff --git a/python-avd/tests/pyavd/schema/test_avdschema_bool.py b/python-avd/tests/pyavd/schema/test_avdschema_bool.py
index 486969362b8..73813ec4d19 100644
--- a/python-avd/tests/pyavd/schema/test_avdschema_bool.py
+++ b/python-avd/tests/pyavd/schema/test_avdschema_bool.py
@@ -23,7 +23,7 @@
"convert_types": ["int", "str"], # Part of meta schema but not implemented in converter
"default": True,
"valid_values": [True],
- "dynamic_valid_values": "valid_booleans", # Part of meta schema but not implemented in converter
+ "dynamic_valid_values": ["valid_booleans"], # Part of meta schema but not implemented in converter
"required": True,
"description": "Some boolean",
"display_name": "Boolean",
diff --git a/python-avd/tests/pyavd/schema/test_avdschema_int.py b/python-avd/tests/pyavd/schema/test_avdschema_int.py
index b0a047177de..61caacd0dbc 100644
--- a/python-avd/tests/pyavd/schema/test_avdschema_int.py
+++ b/python-avd/tests/pyavd/schema/test_avdschema_int.py
@@ -26,7 +26,7 @@
"min": 2,
"max": 20,
"valid_values": [0, 11, 22],
- "dynamic_valid_values": "valid_values", # Part of meta schema but not implemented in converter
+ "dynamic_valid_values": ["valid_values"], # Part of meta schema but not implemented in converter
"required": True,
"description": "Some integer",
"display_name": "Integer",
diff --git a/python-avd/tests/pyavd/schema/test_avdschema_str.py b/python-avd/tests/pyavd/schema/test_avdschema_str.py
index 470c6415d66..fcbf94a3e6d 100644
--- a/python-avd/tests/pyavd/schema/test_avdschema_str.py
+++ b/python-avd/tests/pyavd/schema/test_avdschema_str.py
@@ -29,7 +29,7 @@
"convert_to_lower_case": True,
"max_length": 4,
"min_length": 2,
- "dynamic_valid_values": "valid_strings", # Part of meta schema but not implemented in converter
+ "dynamic_valid_values": ["valid_strings"], # Part of meta schema but not implemented in converter
"pattern": "[abf14t].*",
"required": True,
"description": "Some string",
diff --git a/python-avd/tests/schema_tools/artifacts/eos_designs.schema.yml b/python-avd/tests/schema_tools/artifacts/eos_designs.schema.yml
index 6ef9fc56187..574120fcab8 100644
--- a/python-avd/tests/schema_tools/artifacts/eos_designs.schema.yml
+++ b/python-avd/tests/schema_tools/artifacts/eos_designs.schema.yml
@@ -2639,7 +2639,8 @@ keys:
documentation_options:
table: type-setting
type: str
- dynamic_valid_values: node_type_keys.type
+ dynamic_valid_values:
+ - node_type_keys.type
description: 'The `type:` variable needs to be defined for each device in the
fabric.