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.