diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index 06c454235c4..0d9fbe6ff2d 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -138,33 +138,17 @@ def publish_definition( """ Publish a generated definition. - :param cmd: :param client: :type client: HybridNetworkManagementClient :param - definition_type: VNF or CNF :param config_ - file: - Path to the config file for the NFDV :param definition_file: Optional path to a - bicep template to deploy, in case the user wants to edit the - built NFDV template. If omitted, the default built NFDV - template will be used. :param parameters_json_ - file: - Optional path to a parameters file for the bicep file, in case - the user wants to edit the built NFDV template. If omitted, - parameters from config will be turned into parameters for the - bicep file :param manifest_ - file: - Optional path to an override bicep template to deploy - manifests :param manifest_parameters_json_ - file: :param cmd: :param client: :type client: HybridNetworkManagementClient :param definition_type: VNF or CNF :param config_file: Path to the config file for the NFDV :param definition_file: Optional path to a bicep template to deploy, in case the - user wants to edit the built NFDV template. If omitted, the default - built NFDV template will be used. + user wants to edit the built NFDV template. + If omitted, the default built NFDV template will be used. :param parameters_json_file: Optional path to a parameters file for the bicep file, - in case the user wants to edit the built NFDV template. If omitted, - parameters from config will be turned into parameters for the bicep file + in case the user wants to edit the built NFDV template. If omitted, + parameters from config will be turned into parameters for the bicep file :param manifest_file: Optional path to an override bicep template to deploy manifests :param manifest_parameters_json_file: Optional path to an override bicep parameters diff --git a/src/aosm/azext_aosm/generate_nfd/cnf_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/cnf_nfd_generator.py index 8d8ce10f1d0..f77acd637bf 100644 --- a/src/aosm/azext_aosm/generate_nfd/cnf_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/cnf_nfd_generator.py @@ -25,12 +25,14 @@ CNF_MANIFEST_JINJA2_SOURCE_TEMPLATE, CONFIG_MAPPINGS, DEPLOYMENT_PARAMETER_MAPPING_REGEX, + IMAGE_NAME_AND_VERSION_REGEX, + IMAGE_PATH_REGEX, DEPLOYMENT_PARAMETERS, GENERATED_VALUES_MAPPINGS, - IMAGE_LINE_REGEX, - IMAGE_PULL_SECRET_LINE_REGEX, SCHEMA_PREFIX, SCHEMAS, + IMAGE_PULL_SECRETS_START_STRING, + IMAGE_START_STRING ) from azext_aosm.util.utils import input_ack @@ -110,24 +112,28 @@ def generate_nfd(self) -> None: # Get all image line matches for files in the chart. # Do this here so we don't have to do it multiple times. image_line_matches = self.find_pattern_matches_in_chart( - helm_package, IMAGE_LINE_REGEX + helm_package, IMAGE_START_STRING ) + # Creates a flattened list of image registry paths to prevent set error + image_registry_paths = [] + for registry_path in image_line_matches: + image_registry_paths += registry_path[0] # Generate the NF application configuration for the chart # passed to jinja2 renderer to render bicep template self.nf_application_configurations.append( self.generate_nf_application_config( helm_package, - image_line_matches, + image_registry_paths, self.find_pattern_matches_in_chart( - helm_package, IMAGE_PULL_SECRET_LINE_REGEX + helm_package, IMAGE_PULL_SECRETS_START_STRING ), ) ) # Workout the list of artifacts for the chart and # update the list for the NFD with any unique artifacts. chart_artifacts = self.get_artifact_list( - helm_package, set(image_line_matches) + helm_package, image_line_matches ) self.artifacts += [ a for a in chart_artifacts if a not in self.artifacts @@ -345,21 +351,22 @@ def copy_to_output_folder(self) -> None: def generate_nf_application_config( self, helm_package: HelmPackageConfig, - image_line_matches: List[Tuple[str, ...]], + image_registry_path: List[str], image_pull_secret_line_matches: List[Tuple[str, ...]], ) -> Dict[str, Any]: """Generate NF application config.""" (name, version) = self.get_chart_name_and_version(helm_package) - registryValuesPaths = set({m[0] for m in image_line_matches}) - imagePullSecretsValuesPaths = set(image_pull_secret_line_matches) + + registry_values_paths = set(image_registry_path) + image_pull_secrets_values_paths = set(image_pull_secret_line_matches) return { "name": helm_package.name, "chartName": name, "chartVersion": version, "dependsOnProfile": helm_package.depends_on, - "registryValuesPaths": list(registryValuesPaths), - "imagePullSecretsValuesPaths": list(imagePullSecretsValuesPaths), + "registryValuesPaths": list(registry_values_paths), + "imagePullSecretsValuesPaths": list(image_pull_secrets_values_paths), "valueMappingsPath": self.jsonify_value_mappings(helm_package), } @@ -375,22 +382,37 @@ def _find_yaml_files(self, directory) -> Iterator[str]: yield os.path.join(root, file) def find_pattern_matches_in_chart( - self, helm_package: HelmPackageConfig, pattern: str + self, helm_package: HelmPackageConfig, start_string: str ) -> List[Tuple[str, ...]]: """ Find pattern matches in Helm chart, using provided REGEX pattern. - param helm_package: The helm package config. param pattern: The regex pattern to - match. + param helm_package: The helm package config. + param start_string: The string to search for, either imagePullSecrets: or image: + + If searching for imagePullSecrets, + returns list of lists containing image pull secrets paths, + e.g. Values.foo.bar.imagePullSecret + + If searching for image, + returns list of tuples containing the list of image paths and the name and version of the image. + e.g. (Values.foo.bar.repoPath, foo, 1.2.3) """ chart_dir = os.path.join(self._tmp_folder_name, helm_package.name) matches = [] + path = [] for file in self._find_yaml_files(chart_dir): with open(file, "r", encoding="UTF-8") as f: - contents = f.read() - matches += re.findall(pattern, contents) - + for line in f: + if start_string in line: + path = re.findall(IMAGE_PATH_REGEX, line) + # If "image:", search for chart name and version + if start_string == IMAGE_START_STRING: + name_and_version = re.search(IMAGE_NAME_AND_VERSION_REGEX, line) + matches.append((path, name_and_version.group(1), name_and_version.group(2))) + else: + matches += path return matches def get_artifact_list( @@ -411,7 +433,6 @@ def get_artifact_list( "version": chart_version, } artifact_list.append(helm_artifact) - for match in image_line_matches: artifact_list.append( { @@ -438,7 +459,6 @@ def get_chart_mapping_schema( values_schema = os.path.join( self._tmp_folder_name, helm_package.name, "values.schema.json" ) - if not os.path.exists(mappings_path): raise InvalidTemplateError( f"ERROR: The helm package '{helm_package.name}' does not have a valid values mappings file. \ @@ -447,8 +467,8 @@ def get_chart_mapping_schema( ) if not os.path.exists(values_schema): raise InvalidTemplateError( - f"ERROR: The helm package '{helm_package.name}' is missing values.schema.json. \ - Please fix this and run the command again." + f"ERROR: The helm package '{helm_package.name}' is missing values.schema.json.\n\ + Please fix this and run the command again." ) with open(mappings_path, "r", encoding="utf-8") as stream: @@ -499,6 +519,9 @@ def find_deploy_params( otherwise the final_schema as far as we have got. """ original_schema_nested_dict = schema_nested_dict + # if given a blank mapping file, return empty schema + if nested_dict is None: + return {} for k, v in nested_dict.items(): # if value is a string and contains deployParameters. if isinstance(v, str) and re.search(DEPLOYMENT_PARAMETER_MAPPING_REGEX, v): diff --git a/src/aosm/azext_aosm/util/constants.py b/src/aosm/azext_aosm/util/constants.py index 2fcdb0e6cca..c5274b8ee93 100644 --- a/src/aosm/azext_aosm/util/constants.py +++ b/src/aosm/azext_aosm/util/constants.py @@ -10,7 +10,7 @@ NSD = "nsd" SCHEMA = "schema" -## TODO pk5: clean up these names +# TODO pk5: clean up these names # Names of files used in the repo NSD_DEFINITION_BICEP_SOURCE_TEMPLATE = "nsd_template.bicep" @@ -63,8 +63,14 @@ "type": "object", "properties": {}, } -IMAGE_LINE_REGEX = ( - r"image: \{\{ .Values.(.+?) \}\}/(.+?):(\d+\.\d+\.\d+(-\w+)?(\.\d+)?)" -) -IMAGE_PULL_SECRET_LINE_REGEX = r"imagePullSecrets: \[name: \{\{ .Values.(.+?) \}\}\]" + +# For CNF NFD Generator +# To match the image path if image: is present in the yaml file +IMAGE_START_STRING = "image:" +IMAGE_PATH_REGEX = r".Values\.([^\s})]*)" + +# To match the image name and version if imagePullSecrets: is present in the yaml file +IMAGE_PULL_SECRETS_START_STRING = "imagePullSecrets:" +IMAGE_NAME_AND_VERSION_REGEX = r"\/([^\s]*):([^\s)\"}]*)" + DEPLOYMENT_PARAMETER_MAPPING_REGEX = r"\{deployParameters.(.+?)\}"