From d8c0d451b2817a3dc21d09a596fded18c6af6cc7 Mon Sep 17 00:00:00 2001 From: Claus Holbech Date: Tue, 23 Jul 2024 14:57:19 +0200 Subject: [PATCH] Feat(cv_deploy): Add CV Pathfinder AVT hop count to metadata studio (#4071) Co-authored-by: gmuloc --- ...stom-control-plane-policy-pathfinder-1.yml | 1 + .../cv-pathfinder-pathfinder.yml | 1 + .../cv-pathfinder-pathfinder1.yml | 1 + .../cv-pathfinder-pathfinder2.yml | 1 + .../docs/tables/metadata.md | 2 ++ .../deploy_cv_pathfinder_metadata_to_cv.py | 20 +++++++++++++++++-- .../schema/eos_cli_config_gen.jsonschema.json | 4 ++++ .../schema/eos_cli_config_gen.schema.yml | 2 ++ .../schema_fragments/metadata.schema.yml | 2 ++ .../schema/eos_designs.jsonschema.json | 4 ++++ .../metadata/cv_pathfinder.py | 1 + 11 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-custom-control-plane-policy-pathfinder-1.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-custom-control-plane-policy-pathfinder-1.yml index 910d54dc249..1c857e0f52d 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-custom-control-plane-policy-pathfinder-1.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-custom-control-plane-policy-pathfinder-1.yml @@ -534,6 +534,7 @@ metadata: avts: - constraints: jitter: 5 + hop_count: lowest id: 254 name: CUSTOM-CP-POLICY pathgroups: diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder.yml index 493df9cf002..0c28bd73a94 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder.yml @@ -648,6 +648,7 @@ metadata: avts: - constraints: jitter: 42 + hop_count: lowest id: 2 name: PROD-AVT-POLICY-VOICE pathgroups: diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder1.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder1.yml index 8416f2bd6d5..2f3877600b3 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder1.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder1.yml @@ -643,6 +643,7 @@ metadata: avts: - constraints: jitter: 42 + hop_count: lowest id: 2 name: PROD-AVT-POLICY-VOICE pathgroups: diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder2.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder2.yml index 8c7c14e5fb4..0b25ebf6f0e 100644 --- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder2.yml +++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/cv-pathfinder-pathfinder2.yml @@ -671,6 +671,7 @@ metadata: avts: - constraints: jitter: 42 + hop_count: lowest id: 2 name: PROD-AVT-POLICY-VOICE pathgroups: diff --git a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/metadata.md b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/metadata.md index c97504314ab..4e4a927ae17 100644 --- a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/metadata.md +++ b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/metadata.md @@ -60,6 +60,7 @@ | [              jitter](## "metadata.cv_pathfinder.vrfs.[].avts.[].constraints.jitter") | Integer | | | | | | [              latency](## "metadata.cv_pathfinder.vrfs.[].avts.[].constraints.latency") | Integer | | | | | | [              lossrate](## "metadata.cv_pathfinder.vrfs.[].avts.[].constraints.lossrate") | String | | | | | + | [              hop_count](## "metadata.cv_pathfinder.vrfs.[].avts.[].constraints.hop_count") | String | | | | | | [            description](## "metadata.cv_pathfinder.vrfs.[].avts.[].description") | String | | | | | | [            id](## "metadata.cv_pathfinder.vrfs.[].avts.[].id") | Integer | | | | | | [            name](## "metadata.cv_pathfinder.vrfs.[].avts.[].name") | String | | | | | @@ -144,6 +145,7 @@ jitter: latency: lossrate: + hop_count: description: id: name: diff --git a/python-avd/pyavd/_cv/workflows/deploy_cv_pathfinder_metadata_to_cv.py b/python-avd/pyavd/_cv/workflows/deploy_cv_pathfinder_metadata_to_cv.py index 8b5d89c27d4..8d468e83ce7 100644 --- a/python-avd/pyavd/_cv/workflows/deploy_cv_pathfinder_metadata_to_cv.py +++ b/python-avd/pyavd/_cv/workflows/deploy_cv_pathfinder_metadata_to_cv.py @@ -34,6 +34,11 @@ def is_pathfinder_location_supported(studio_schema: InputSchema) -> bool: return attributes.issubset(pathfinder_group_fields) +def is_avt_hop_count_supported(studio_schema: InputSchema) -> bool: + """Detect if AVT hop count is supported by the metadata studio""" + return bool(get_v2(studio_schema, "fields.values.avtHopCount")) + + def is_internet_exit_zscaler_supported(studio_schema: InputSchema) -> bool: """Detect if zscaler internet exit is supported by the metadata studio""" return bool(get_v2(studio_schema, "fields.values.zscaler")) @@ -58,10 +63,12 @@ async def get_metadata_studio_schema(result: DeployToCvResult, cv_client: CVClie return studio_schema -def update_general_metadata(metadata: dict, studio_inputs: dict) -> None: +def update_general_metadata(metadata: dict, studio_inputs: dict, studio_schema: InputSchema) -> list[str]: """ In-place update general metadata in studio_inputs. """ + warnings = [] + # Temporary fix for default values in metadata studio for vrf in get(metadata, "vrfs", default=[]): for avt in get(vrf, "avts", default=[]): @@ -69,6 +76,13 @@ def update_general_metadata(metadata: dict, studio_inputs: dict) -> None: constraints.setdefault("latency", 4294967295) constraints.setdefault("jitter", 4294967295) constraints.setdefault("lossrate", 99.0) + if is_avt_hop_count_supported(studio_schema): + constraints["hopCount"] = constraints.pop("hop_count", "") + elif constraints.pop("hop_count", ""): + # hop count is set but not supported by metadata studio. + warning = "deploy_cv_pathfinder_metadata_to_cv: Ignoring AVT hop-count information since it is not supported by metadata studio." + LOGGER.info(warning) + warnings.append(warning) studio_inputs.update( { @@ -85,6 +99,8 @@ def update_general_metadata(metadata: dict, studio_inputs: dict) -> None: } ) + return warnings + def upsert_pathfinder(metadata: dict, device: CVDevice, studio_inputs: dict, studio_schema: InputSchema) -> list[str]: """ @@ -329,7 +345,7 @@ async def deploy_cv_pathfinder_metadata_to_cv(cv_pathfinder_metadata: list[CVPat if pathfinders: # All pathfinders must have the same be general metadata, so we just set it in the studio based on the first one. - update_general_metadata(metadata=pathfinders[0].metadata, studio_inputs=studio_inputs) + result.warnings.extend(update_general_metadata(metadata=pathfinders[0].metadata, studio_inputs=studio_inputs, studio_schema=studio_schema)) for pathfinder in pathfinders: result.warnings.extend( 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 4f6710fb87c..4c3e635f52e 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 @@ -12047,6 +12047,10 @@ "lossrate": { "type": "string", "title": "Lossrate" + }, + "hop_count": { + "type": "string", + "title": "Hop Count" } }, "additionalProperties": false, 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 f13704ad8b4..9e1cc05ed29 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 @@ -7138,6 +7138,8 @@ keys: type: str convert_types: - float + hop_count: + type: str description: type: str id: diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/metadata.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/metadata.schema.yml index 11de6a17dca..2113dcf19bd 100644 --- a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/metadata.schema.yml +++ b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/metadata.schema.yml @@ -170,6 +170,8 @@ keys: type: str convert_types: - float + hop_count: + type: str description: type: str id: 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 6074177e863..673a63c99f3 100644 --- a/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json +++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.jsonschema.json @@ -29955,6 +29955,10 @@ "lossrate": { "type": "string", "title": "Lossrate" + }, + "hop_count": { + "type": "string", + "title": "Hop Count" } }, "additionalProperties": false, diff --git a/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_pathfinder.py b/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_pathfinder.py index a4f255a5b67..fd484eafd2a 100644 --- a/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_pathfinder.py +++ b/python-avd/pyavd/_eos_designs/structured_config/metadata/cv_pathfinder.py @@ -166,6 +166,7 @@ def _metadata_vrfs(self: AvdStructuredConfigMetadata) -> list: "jitter": lb_policy.get("jitter"), "latency": lb_policy.get("latency"), "lossrate": float(lb_policy["loss_rate"]) if "loss_rate" in lb_policy else None, + "hop_count": "lowest" if lb_policy.get("lowest_hop_count") else None, }, "description": "", # TODO: Not sure we have this field anywhere "id": profile["id"],