From 7303144a116260b24f107d586124dff8aca84625 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 23 Feb 2024 12:03:06 +0000 Subject: [PATCH 1/5] added semver checking to input config validation; moved split image path to utils --- .../cli_handlers/onboarding_nexus_vnf_handler.py | 11 ++--------- src/aosm/azext_aosm/common/constants.py | 1 + src/aosm/azext_aosm/common/utils.py | 13 +++++++++++-- .../onboarding_vnf_input_config.py | 7 ++++++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py b/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py index 32a2b78df68..600465c30b2 100644 --- a/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py +++ b/src/aosm/azext_aosm/cli_handlers/onboarding_nexus_vnf_handler.py @@ -36,7 +36,7 @@ from azext_aosm.inputs.arm_template_input import ArmTemplateInput from azext_aosm.inputs.nexus_image_input import NexusImageFileInput from .onboarding_vnf_handler import OnboardingVNFCLIHandler -from azext_aosm.common.utils import render_bicep_contents_from_j2, get_template_path +from azext_aosm.common.utils import render_bicep_contents_from_j2, get_template_path, split_image_path logger = get_logger(__name__) @@ -79,8 +79,7 @@ def _get_processor_list(self) -> [BaseInputProcessor]: ) # For each image, instantiate image processor for image in self.config.images: - (source_acr_registry, name, version) = self._split_image_path(image) - + (source_acr_registry, name, version) = split_image_path(image) image_input = NexusImageFileInput( artifact_name=name, artifact_version=version, @@ -122,12 +121,6 @@ def build_all_parameters_json(self) -> JSONDefinitionElementBuilder: ) return base_file - def _split_image_path(self, image) -> "tuple[str, str, str]": - """Split the image path into source acr registry, name and version.""" - (source_acr_registry, name_and_version) = image.split("/", 2) - (name, version) = name_and_version.split(":", 2) - return (source_acr_registry, name, version) - def _generate_type_specific_nf_application(self, processor) -> "tuple[list, list]": """Generate the type specific nf application.""" arm_nf = [] diff --git a/src/aosm/azext_aosm/common/constants.py b/src/aosm/azext_aosm/common/constants.py index 7a9f9641815..e42204addbb 100644 --- a/src/aosm/azext_aosm/common/constants.py +++ b/src/aosm/azext_aosm/common/constants.py @@ -79,6 +79,7 @@ class ManifestsExist(str, Enum): CNF_VALUES_SCHEMA_FILENAME = "values.schema.json" CNF_TEMPLATE_FOLDER_NAME = "cnf" +SEMVER_REGEX = r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" ################# # OLD CONSTANTS # ################# diff --git a/src/aosm/azext_aosm/common/utils.py b/src/aosm/azext_aosm/common/utils.py index ec1dd8c5663..ca880169651 100644 --- a/src/aosm/azext_aosm/common/utils.py +++ b/src/aosm/azext_aosm/common/utils.py @@ -2,7 +2,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- - +import re import os import tarfile from pathlib import Path @@ -13,7 +13,7 @@ import tempfile from knack.log import get_logger - +from azext_aosm.common.constants import SEMVER_REGEX from azext_aosm.common.exceptions import InvalidFileTypeError, MissingDependency logger = get_logger(__name__) @@ -123,3 +123,12 @@ def check_tool_installed(tool_name: str) -> None: """ if shutil.which(tool_name) is None: raise MissingDependency(f"You must install {tool_name} to use this command.") + +def split_image_path(image) -> "tuple[str, str, str]": + """Split the image path into source acr registry, name and version.""" + (source_acr_registry, name_and_version) = image.split("/", 2) + (name, version) = name_and_version.split(":", 2) + return (source_acr_registry, name, version) + +def is_semver(string): + return re.match(SEMVER_REGEX, string) is not None diff --git a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py index 13984a07d92..bb81261307e 100644 --- a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py +++ b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py @@ -3,7 +3,6 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- from __future__ import annotations - from dataclasses import dataclass, field from typing import List @@ -13,6 +12,7 @@ from azext_aosm.configuration_models.onboarding_nfd_base_input_config import ( OnboardingNFDBaseInputConfig, ) +from azext_aosm.common.utils import split_image_path, is_semver @dataclass @@ -231,6 +231,11 @@ def validate(self): raise ValidationError("arm_template must be set") if not self.images: raise ValidationError("You must include at least one image") + for image in self.images: + (_, _, version) = split_image_path(image) + if not is_semver(version): + raise ValidationError(f"{image} has invalid version '{version}'.\n" + "Allowed formats are major.minor.patch") if not self.arm_templates: raise ValidationError("You must include at least one arm template") for arm_template in self.arm_templates: From aea0e0f2ed3a12f0b2655c13e8ba7f273c1ae474 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 26 Feb 2024 15:01:00 +0000 Subject: [PATCH 2/5] changed semver regex; renamed function --- src/aosm/azext_aosm/common/constants.py | 3 ++- src/aosm/azext_aosm/common/utils.py | 12 +++++++++--- .../onboarding_vnf_input_config.py | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/aosm/azext_aosm/common/constants.py b/src/aosm/azext_aosm/common/constants.py index e42204addbb..fd04aafaa2d 100644 --- a/src/aosm/azext_aosm/common/constants.py +++ b/src/aosm/azext_aosm/common/constants.py @@ -79,7 +79,8 @@ class ManifestsExist(str, Enum): CNF_VALUES_SCHEMA_FILENAME = "values.schema.json" CNF_TEMPLATE_FOLDER_NAME = "cnf" -SEMVER_REGEX = r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" +NEXUS_IMAGE_REGEX = r"^[\~]?(\d+)\.(\d+)\.(\d+)$" +# SEMVER_REGEX = r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" ################# # OLD CONSTANTS # ################# diff --git a/src/aosm/azext_aosm/common/utils.py b/src/aosm/azext_aosm/common/utils.py index ca880169651..6ee30f8a7f3 100644 --- a/src/aosm/azext_aosm/common/utils.py +++ b/src/aosm/azext_aosm/common/utils.py @@ -13,7 +13,7 @@ import tempfile from knack.log import get_logger -from azext_aosm.common.constants import SEMVER_REGEX +from azext_aosm.common.constants import NEXUS_IMAGE_REGEX from azext_aosm.common.exceptions import InvalidFileTypeError, MissingDependency logger = get_logger(__name__) @@ -130,5 +130,11 @@ def split_image_path(image) -> "tuple[str, str, str]": (name, version) = name_and_version.split(":", 2) return (source_acr_registry, name, version) -def is_semver(string): - return re.match(SEMVER_REGEX, string) is not None +def is_valid_nexus_image_version(string): + """Check if image version is valid. + + This is based on validation in pez repo. + It requires the image version to be major.minor.path, + but does enforce full semver validation. + """ + return re.match(NEXUS_IMAGE_REGEX, string) is not None diff --git a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py index bb81261307e..cb4cffa04f3 100644 --- a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py +++ b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py @@ -12,7 +12,7 @@ from azext_aosm.configuration_models.onboarding_nfd_base_input_config import ( OnboardingNFDBaseInputConfig, ) -from azext_aosm.common.utils import split_image_path, is_semver +from azext_aosm.common.utils import split_image_path, is_valid_nexus_image_version @dataclass @@ -233,7 +233,7 @@ def validate(self): raise ValidationError("You must include at least one image") for image in self.images: (_, _, version) = split_image_path(image) - if not is_semver(version): + if not is_valid_nexus_image_version(version): raise ValidationError(f"{image} has invalid version '{version}'.\n" "Allowed formats are major.minor.patch") if not self.arm_templates: From 42290b3680254037ca056c301b504ceaf046d513 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 26 Feb 2024 15:13:57 +0000 Subject: [PATCH 3/5] fixed typo --- src/aosm/azext_aosm/common/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aosm/azext_aosm/common/utils.py b/src/aosm/azext_aosm/common/utils.py index 6ee30f8a7f3..46e86eff0ec 100644 --- a/src/aosm/azext_aosm/common/utils.py +++ b/src/aosm/azext_aosm/common/utils.py @@ -135,6 +135,6 @@ def is_valid_nexus_image_version(string): This is based on validation in pez repo. It requires the image version to be major.minor.path, - but does enforce full semver validation. + but does not enforce full semver validation. """ return re.match(NEXUS_IMAGE_REGEX, string) is not None From 1026a9ea0f4e8e498cfa311ecfe4f0de17868242 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 26 Feb 2024 15:14:49 +0000 Subject: [PATCH 4/5] markups --- .../configuration_models/onboarding_vnf_input_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py index cb4cffa04f3..83246efd358 100644 --- a/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py +++ b/src/aosm/azext_aosm/configuration_models/onboarding_vnf_input_config.py @@ -235,7 +235,7 @@ def validate(self): (_, _, version) = split_image_path(image) if not is_valid_nexus_image_version(version): raise ValidationError(f"{image} has invalid version '{version}'.\n" - "Allowed formats are major.minor.patch") + "Allowed format is major.minor.patch") if not self.arm_templates: raise ValidationError("You must include at least one arm template") for arm_template in self.arm_templates: From 4ec2b6c107bdb2bbc256a244d92cd81eb616be04 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 26 Feb 2024 15:15:29 +0000 Subject: [PATCH 5/5] fix typo --- src/aosm/azext_aosm/common/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aosm/azext_aosm/common/utils.py b/src/aosm/azext_aosm/common/utils.py index 46e86eff0ec..493e2d59b6e 100644 --- a/src/aosm/azext_aosm/common/utils.py +++ b/src/aosm/azext_aosm/common/utils.py @@ -134,7 +134,7 @@ def is_valid_nexus_image_version(string): """Check if image version is valid. This is based on validation in pez repo. - It requires the image version to be major.minor.path, + It requires the image version to be major.minor.patch, but does not enforce full semver validation. """ return re.match(NEXUS_IMAGE_REGEX, string) is not None