From bf0a29f9744b0abb65b200133f2af574b479edeb Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 13:10:01 +0100 Subject: [PATCH 01/13] artifact manifests separate --- src/aosm/azext_aosm/_configuration.py | 78 +++++++++++----- src/aosm/azext_aosm/_constants.py | 1 + src/aosm/azext_aosm/_help.py | 13 ++- src/aosm/azext_aosm/_params.py | 15 ++++ src/aosm/azext_aosm/commands.py | 1 + src/aosm/azext_aosm/custom.py | 90 ++++++++++++++----- src/aosm/azext_aosm/deploy/artifact.py | 20 +++-- .../azext_aosm/deploy/artifact_manifest.py | 2 +- src/aosm/azext_aosm/deploy/deploy_with_arm.py | 85 +++++++++++++----- src/aosm/azext_aosm/deploy/pre_deploy.py | 48 ++++++++++ .../templates/vnfartifactmanifests.bicep | 70 +++++++++++++++ .../templates/vnfdefinition.bicep | 38 -------- .../generate_nfd/vnf_bicep_nfd_generator.py | 15 +++- 13 files changed, 362 insertions(+), 114 deletions(-) create mode 100644 src/aosm/azext_aosm/generate_nfd/templates/vnfartifactmanifests.bicep diff --git a/src/aosm/azext_aosm/_configuration.py b/src/aosm/azext_aosm/_configuration.py index cd5a6ed3116..d87b391f4eb 100644 --- a/src/aosm/azext_aosm/_configuration.py +++ b/src/aosm/azext_aosm/_configuration.py @@ -1,36 +1,54 @@ from dataclasses import dataclass -from typing import Optional, Any +from typing import Dict, Optional, Any from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError -from ._constants import VNF, CNF, NSD +from pathlib import Path +from azext_aosm._constants import ( + VNF_DEFINITION_OUTPUT_BICEP_PREFIX, + VNF, + CNF, + NSD +) + +DESCRIPTION_MAP: Dict[str,str] = { + "publisher_name": "Name of the Publisher resource you want you definition published to", + "publisher_resource_group_name": "Resource group the Publisher resource is in or you want it to be in", + "nf_name": "Name of NF definition", + "version": "Version of the NF definition", + "acr_artifact_store_name":"Name of the ACR Artifact Store resource", + "location": "Azure location of the resources", + "blob_artifact_store_name": "Name of the storage account Artifact Store resource", + "artifact_name": "Name of the artifact", + "file_path": "Optional. File path of the artifact you wish to upload from your local disk. Delete if not required.", + "blob_sas_url": "Optional. SAS URL of the blob artifact you wish to copy to your Artifact Store. Delete if not required.", + "artifact_version": ( + "Version of the artifact. For VHDs this must be in format A-B-C. " + "For ARM templates this must be in format A.B.C" + ) +} @dataclass class ArtifactConfig: - artifact_name: str = "Name of the artifact" + artifact_name: str = DESCRIPTION_MAP["artifact_name"] + # artifact.py checks for the presence of the default descriptions, change there if + # you change the descriptions. file_path: Optional[ str - ] = "File path of the artifact you wish to upload from your local disk" + ] = DESCRIPTION_MAP["file_path"] blob_sas_url: Optional[ str - ] = "SAS URL of the blob artifact you wish to copy to your Artifact Store" - version: str = ( - "Version of the artifact. For VHDs this must be in format A-B-C. " - "For ARM templates this must be in format A.B.C" - ) + ] = DESCRIPTION_MAP["blob_sas_url"] + version: str = DESCRIPTION_MAP["artifact_version"] @dataclass class Configuration: - publisher_name: str = ( - "Name of the Publisher resource you want you definition published to" - ) - publisher_resource_group_name: str = ( - "Resource group the Publisher resource is in or you want it to be in" - ) - nf_name: str = "Name of NF definition" - version: str = "Version of the NF definition" - acr_artifact_store_name: str = "Name of the ACR Artifact Store resource" - location: str = "Azure location of the resources" + publisher_name: str = DESCRIPTION_MAP["publisher_name"] + publisher_resource_group_name: str = DESCRIPTION_MAP["publisher_resource_group_name"] + nf_name: str = DESCRIPTION_MAP["nf_name"] + version: str = DESCRIPTION_MAP["version"] + acr_artifact_store_name: str = DESCRIPTION_MAP["acr_artifact_store_name"] + location: str = DESCRIPTION_MAP["location"] @property def nfdg_name(self) -> str: @@ -45,9 +63,7 @@ def acr_manifest_name(self) -> str: @dataclass class VNFConfiguration(Configuration): - blob_artifact_store_name: str = ( - "Name of the storage account Artifact Store resource" - ) + blob_artifact_store_name: str = DESCRIPTION_MAP["blob_artifact_store_name"] arm_template: Any = ArtifactConfig() vhd: Any = ArtifactConfig() @@ -68,9 +84,17 @@ def __post_init__(self): def sa_manifest_name(self) -> str: """Return the Storage account manifest name from the NFD name.""" return f"{self.nf_name}-sa-manifest-{self.version.replace('.', '-')}" + + @property + def build_output_folder_name(self) -> str: + """Return the local folder for generating the bicep template to.""" + arm_template_path = self.arm_template.file_path + return ( + f"{VNF_DEFINITION_OUTPUT_BICEP_PREFIX}{Path(str(arm_template_path)).stem}" + ) -def get_configuration(definition_type, config_as_dict=None) -> Configuration: +def get_configuration(definition_type: str, config_as_dict: Optional[Dict[Any,Any]]=None) -> Configuration: if config_as_dict is None: config_as_dict = {} @@ -112,3 +136,11 @@ def validate_configuration(config: Configuration) -> None: raise ValidationError( "Config validation error. ARM template artifact version should be in format A.B.C" ) + + if not ((config.vhd.file_path or config.vhd.blob_sas_url) or ( + config.vhd.file_path == DESCRIPTION_MAP["file_path"] and + config.vhd.blob_sas_url == DESCRIPTION_MAP["blob_sas_url"]) + ): + raise ValidationError( + "Config validation error. VHD config must have either a local filepath or a blob SAS URL" + ) diff --git a/src/aosm/azext_aosm/_constants.py b/src/aosm/azext_aosm/_constants.py index 8b232eff0bf..6933f42f511 100644 --- a/src/aosm/azext_aosm/_constants.py +++ b/src/aosm/azext_aosm/_constants.py @@ -13,6 +13,7 @@ # Names of files used in the repo VNF_DEFINITION_BICEP_SOURCE_TEMPLATE = "vnfdefinition.bicep" +VNF_MANIFEST_BICEP_SOURCE_TEMPLATE = "vnfartifactmanifests.bicep" VNF_DEFINITION_OUTPUT_BICEP_PREFIX = "nfd-bicep-" # Provisioning States diff --git a/src/aosm/azext_aosm/_help.py b/src/aosm/azext_aosm/_help.py index d5169d49c0d..df276d4f8bd 100644 --- a/src/aosm/azext_aosm/_help.py +++ b/src/aosm/azext_aosm/_help.py @@ -21,6 +21,13 @@ short-summary: Manage AOSM publisher definitions. """ +helps[ + "aosm definition generate-config" +] = """ + type: command + short-summary: Generate configuration file for building an AOSM publisher definition. +""" + helps[ "aosm definition build" ] = """ @@ -29,12 +36,14 @@ """ helps[ - "aosm definition generate-config" + "aosm definition publish" ] = """ type: command - short-summary: Generate configuration file for building an AOSM publisher definition. + short-summary: Publish a pre-built AOSM publisher definition. """ + + helps[ "aosm definition delete" ] = """ diff --git a/src/aosm/azext_aosm/_params.py b/src/aosm/azext_aosm/_params.py index c9339763f4d..622f4998c76 100644 --- a/src/aosm/azext_aosm/_params.py +++ b/src/aosm/azext_aosm/_params.py @@ -42,6 +42,21 @@ def load_arguments(self: AzCommandsLoader, _): arg_type=get_three_state_flag(), help="Also delete artifact stores, NFD Group and Publisher. Use with care.", ) + c.argument( + "bicep_file", + options_list=["--bicep-file", "-b"], + type=file_type, + completer=FilesCompleter(allowednames="*.json"), + help="Optional path to a bicep file to publish. Use to override publish of the built definition with an alternative file.", + ) + c.argument( + "parameters_json_file", + options_list=["--parameters-file", "-p"], + type=file_type, + completer=FilesCompleter(allowednames="*.json"), + help="Optional path to a parameters file for the bicep definition file. Use to override publish of the built definition and config with alternative parameters.", + ) + with self.argument_context("aosm generate-config") as c: c.argument( diff --git a/src/aosm/azext_aosm/commands.py b/src/aosm/azext_aosm/commands.py index d57a4b9db3b..66b42311cbf 100644 --- a/src/aosm/azext_aosm/commands.py +++ b/src/aosm/azext_aosm/commands.py @@ -21,6 +21,7 @@ def load_command_table(self: AzCommandsLoader, _): g.custom_command("build", "build_definition") g.custom_command("delete", "delete_published_definition") g.custom_command("show", "show_publisher") + g.custom_command("publish", "publish_definition") with self.command_group("aosm", is_preview=True): pass diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index f0fdf3a43ba..c18facc45b7 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -6,6 +6,7 @@ import json from dataclasses import asdict from knack.log import get_logger +from typing import Optional from azext_aosm.generate_nfd.cnf_nfd_generator import CnfNfdGenerator from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator @@ -18,6 +19,7 @@ from ._configuration import ( get_configuration, validate_configuration, + Configuration ) @@ -27,8 +29,8 @@ def build_definition( cmd, client: HybridNetworkManagementClient, - definition_type, - config_file, + definition_type: str, + config_file: str, publish=False, ): """Build and optionally publish a definition @@ -44,18 +46,12 @@ def build_definition( :param publish: _description_, defaults to False :type publish: bool, optional """ - with open(config_file, "r", encoding="utf-8") as f: - config_as_dict = json.loads(f.read()) - - apiClientsAndCaches = ApiClientsAndCaches( + api_clients = ApiClientsAndCaches( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) ) - # TODO - this isn't deserializing the config properly - any sub-objects are left - # as a dictionary instead of being converted to the object (e.g. ArtifactConfig) - # se we have to reference them as dictionary values - config = get_configuration(definition_type, config_as_dict) - validate_configuration(config) + config = _get_config_from_file(config_file, definition_type) + # Generate the NFD/NSD and the artifact manifest. _generate_nfd(definition_type=definition_type, config=config) # Write the ARM/bicep template if that's what we are doing @@ -63,26 +59,38 @@ def build_definition( # Publish the definition if publish is true if publish: if definition_type == VNF: - deployer = DeployerViaArm(apiClientsAndCaches, config=config) + deployer = DeployerViaArm(api_clients, config=config) deployer.deploy_vnfd_from_bicep() else: print("TODO - cannot publish CNF or NSD yet.") -def generate_definition_config(_, definition_type, output_file="input.json"): +def generate_definition_config(definition_type: str, output_file: str="input.json"): config = get_configuration(definition_type) config_as_dict = json.dumps(asdict(config), indent=4) with open(output_file, "w", encoding="utf-8") as f: f.write(config_as_dict) print( - "Empty definition configuration has been written to %s", - output_file, + f"Empty definition configuration has been written to {output_file}" ) logger.info( - "Empty definition configuration has been written to %s", - output_file, + f"Empty definition configuration has been written to {output_file}" ) + +def _get_config_from_file(config_file: str, definition_type: str) -> Configuration: + """Read input config file JSON and turn it into a Configuration object. + + :param config_file: path to the file + :param definition_type: VNF, CNF or NSD + :rtype: Configuration + """ + with open(config_file, "r", encoding="utf-8") as f: + config_as_dict = json.loads(f.read()) + + config = get_configuration(definition_type, config_as_dict) + validate_configuration(config) + return config def _generate_nfd(definition_type, config): @@ -105,6 +113,40 @@ def _generate_nfd(definition_type, config): ) nfd_generator.generate_nfd() + +def publish_definition( + cmd, + client: HybridNetworkManagementClient, + definition_type, + config_file, + bicep_file: Optional[str] = None, + parameters_json_file: Optional[str] = None +): + """_summary_ + + :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 bicep_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 + + """ + print("Publishing definition.") + api_clients = ApiClientsAndCaches( + aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) + ) + config = _get_config_from_file(config_file, definition_type) + if definition_type == VNF: + deployer = DeployerViaArm(api_clients, config=config) + deployer.deploy_vnfd_from_bicep(bicep_path=bicep_file, + parameters_json_file=parameters_json_file) def delete_published_definition( @@ -114,10 +156,16 @@ def delete_published_definition( config_file, clean=False, ): - with open(config_file, "r", encoding="utf-8") as f: - config_as_dict = json.loads(f.read()) - config = get_configuration(definition_type, config_as_dict) - validate_configuration(config) + """ + Delete a published definition. + + :param definition_type: CNF or VNF + :param config_file: Path to the config file + :param clean: if True, will delete the NFDG, artifact stores and publisher too. + Defaults to False. Only works if no resources have those as a parent. + Use with care. + """ + config = _get_config_from_file(config_file, definition_type) api_clients = ApiClientsAndCaches( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) diff --git a/src/aosm/azext_aosm/deploy/artifact.py b/src/aosm/azext_aosm/deploy/artifact.py index 057a6f409d1..bbb647182be 100644 --- a/src/aosm/azext_aosm/deploy/artifact.py +++ b/src/aosm/azext_aosm/deploy/artifact.py @@ -7,7 +7,7 @@ from typing import Union from azure.storage.blob import BlobClient -from azext_aosm._configuration import ArtifactConfig +from azext_aosm._configuration import ArtifactConfig, DESCRIPTION_MAP from oras.client import OrasClient logger = get_logger(__name__) @@ -41,11 +41,13 @@ def _upload_to_acr(self, artifact_config: ArtifactConfig) -> None: """ assert type(self.artifact_client) == OrasClient - if "file_path" in artifact_config.keys(): + # If not included in config, the file path value will be the description of + # the field. + if artifact_config.file_path and not artifact_config.file_path == DESCRIPTION_MAP["file_path"]: target = f"{self.artifact_client.remote.hostname.replace('https://', '')}/{self.artifact_name}:{self.artifact_version}" - logger.debug(f"Uploading {artifact_config['file_path']} to {target}") + logger.debug(f"Uploading {artifact_config.file_path} to {target}") self.artifact_client.push( - file=artifact_config["file_path"], + file=artifact_config.file_path, target=target, ) else: @@ -62,14 +64,16 @@ def _upload_to_storage_account(self, artifact_config: ArtifactConfig) -> None: assert type(self.artifact_client) == BlobClient # If the file path is given, upload the artifact, else, copy it from an existing blob. - if "file_path" in artifact_config.keys(): - with open(artifact_config["file_path"], "rb") as artifact: + if artifact_config.file_path and not artifact_config.file_path == DESCRIPTION_MAP["file_path"]: + logger.info("Upload to blob store") + with open(artifact_config.file_path, "rb") as artifact: self.artifact_client.upload_blob(artifact, overwrite=True) logger.info( - f"Successfully uploaded {artifact_config['file_path']} to {self.artifact_client.account_name}" + f"Successfully uploaded {artifact_config.file_path} to {self.artifact_client.account_name}" ) else: - source_blob = BlobClient.from_blob_url(artifact_config["blob_sas_url"]) + logger.info("Copy from SAS URL to blob store") + source_blob = BlobClient.from_blob_url(artifact_config.blob_sas_url) if source_blob.exists(): logger.debug(source_blob.url) diff --git a/src/aosm/azext_aosm/deploy/artifact_manifest.py b/src/aosm/azext_aosm/deploy/artifact_manifest.py index 42a655be533..6dc3c31ea0d 100644 --- a/src/aosm/azext_aosm/deploy/artifact_manifest.py +++ b/src/aosm/azext_aosm/deploy/artifact_manifest.py @@ -49,7 +49,7 @@ def _manifest_credentials(self) -> Any: def _oras_client(self, acr_url: str) -> OrasClient: """ - Returns an OrasClient object for uploading to the artifact str Returns an OrasClient object for uploading to the artifact store ACR.oe ACR. + Returns an OrasClient object for uploading to the artifact store ACR. :param arc_url: URL of the ACR backing the artifact manifest """ diff --git a/src/aosm/azext_aosm/deploy/deploy_with_arm.py b/src/aosm/azext_aosm/deploy/deploy_with_arm.py index c669578b5c4..5748b8cf96f 100644 --- a/src/aosm/azext_aosm/deploy/deploy_with_arm.py +++ b/src/aosm/azext_aosm/deploy/deploy_with_arm.py @@ -7,7 +7,7 @@ import os import shutil import subprocess # noqa -from typing import Any, Dict +from typing import Any, Dict, Optional from knack.log import get_logger from azext_aosm.deploy.artifact_manifest import ArtifactManifestOperator @@ -18,8 +18,8 @@ from azext_aosm.deploy.pre_deploy import PreDeployerViaSDK from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm._constants import ( - VNF_DEFINITION_OUTPUT_BICEP_PREFIX, VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE ) @@ -49,7 +49,10 @@ def __init__( self.config = config self.pre_deployer = PreDeployerViaSDK(apiClientsAndCaches, self.config) - def deploy_vnfd_from_bicep(self) -> None: + def deploy_vnfd_from_bicep(self, + bicep_path: Optional[str] = None, + parameters_json_file: Optional[str] = None + ) -> None: """ Deploy the bicep template defining the VNFD. @@ -60,24 +63,48 @@ def deploy_vnfd_from_bicep(self) -> None: """ assert isinstance(self.config, VNFConfiguration) - # TODO - duplicated from vnf_bicep_nfd_generator and won't work if file exists - arm_template_path = self.config.arm_template.file_path - folder_name = ( - f"{VNF_DEFINITION_OUTPUT_BICEP_PREFIX}{Path(str(arm_template_path)).stem}" - ) - bicep_template_name = VNF_DEFINITION_BICEP_SOURCE_TEMPLATE - bicep_path = os.path.join(folder_name, bicep_template_name) + if not bicep_path: + # User has not passed in a bicep template, so we are deploying the default + # one produced from building the NFDV using this CLI + bicep_path = os.path.join(self.config.build_output_folder_name, + VNF_DEFINITION_BICEP_SOURCE_TEMPLATE) + + if parameters_json_file: + message: str = f"Use parameters from file {parameters_json_file}" + logger.info(message) + print(message) + with open(parameters_json_file, "r", encoding="utf-8") as f: + parameters = json.loads(f.read()) + + else: + # User has not passed in parameters file, so we use the parameters required + # from config for the default bicep template produced from building the + # NFDV using this CLI + logger.debug("Create parameters for default NFDV template.") + parameters = self.construct_vnfd_parameters() - parameters = self.construct_vnfd_parameters() logger.debug(parameters) # Create or check required resources - self.vnfd_predeploy() + deploy_manifest_template = not self.vnfd_predeploy() + if deploy_manifest_template: + print(f"Deploy bicep template for Artifact manifests") + logger.debug("Deploy manifest bicep") + manifest_bicep_path = os.path.join(self.config.build_output_folder_name, + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE) + manifest_params = self.construct_manifest_parameters() + self.deploy_bicep_template(manifest_bicep_path, manifest_params) + else: + print(f"Artifact manifests exist for NFD {self.config.nf_name} " + f"version {self.config.version}") + message = (f"Deploy bicep template for NFD {self.config.nf_name} version {self.config.version} " + f"into {self.config.publisher_resource_group_name} under publisher " + f"{self.config.publisher_name}") + print(message) + logger.info(message) self.deploy_bicep_template(bicep_path, parameters) print( - f"Deployed NFD {self.config.nf_name} version {self.config.version} " - f"into {self.config.publisher_resource_group_name} under publisher " - f"{self.config.publisher_name}" + f"Deployed NFD {self.config.nf_name} version {self.config.version}." ) storage_account_manifest = ArtifactManifestOperator( @@ -102,11 +129,12 @@ def deploy_vnfd_from_bicep(self) -> None: arm_template_artifact.upload(self.config.arm_template) print("Done") - def vnfd_predeploy(self): + def vnfd_predeploy(self) -> bool: """ All the predeploy steps for a VNF. Create publisher, artifact stores and NFDG. VNF specific + return True if artifact manifest already exists, False otherwise """ logger.debug("Ensure all required resources exist") self.pre_deployer.ensure_config_resource_group_exists() @@ -114,6 +142,7 @@ def vnfd_predeploy(self): self.pre_deployer.ensure_acr_artifact_store_exists() self.pre_deployer.ensure_sa_artifact_store_exists() self.pre_deployer.ensure_config_nfdg_exists() + return self.pre_deployer.do_config_artifact_manifests_exist() def construct_vnfd_parameters(self) -> Dict[str, Any]: """ @@ -126,16 +155,31 @@ def construct_vnfd_parameters(self) -> Dict[str, Any]: "publisherName": {"value": self.config.publisher_name}, "acrArtifactStoreName": {"value": self.config.acr_artifact_store_name}, "saArtifactStoreName": {"value": self.config.blob_artifact_store_name}, - "acrManifesteName": {"value": self.config.acr_manifest_name}, - "saManifesteName": {"value": self.config.sa_manifest_name}, "nfName": {"value": self.config.nf_name}, "nfDefinitionGroup": {"value": self.config.nfdg_name}, "nfDefinitionVersion": {"value": self.config.version}, + "vhdVersion": {"value": self.config.vhd.version}, + "armTemplateVersion": {"value": self.config.arm_template.version}, + } + + def construct_manifest_parameters(self) -> Dict[str, Any]: + """ + Create the parmeters dictionary for vnfdefinitions.bicep. VNF specific. + + :param config: The contents of the configuration file. + """ + assert isinstance(self.config, VNFConfiguration) + return { + "publisherName": {"value": self.config.publisher_name}, + "acrArtifactStoreName": {"value": self.config.acr_artifact_store_name}, + "saArtifactStoreName": {"value": self.config.blob_artifact_store_name}, + "acrManifestName": {"value": self.config.acr_manifest_name}, + "saManifestName": {"value": self.config.sa_manifest_name}, "vhdName": {"value": self.config.vhd.artifact_name}, - "vhdVersion": {"value": self.config.vhd.version.}, + "vhdVersion": {"value": self.config.vhd.version}, "armTemplateName": {"value": self.config.arm_template.artifact_name}, "armTemplateVersion": {"value": self.config.arm_template.version}, - } + } def deploy_bicep_template( self, bicep_template_path: str, parameters: Dict[Any, Any] @@ -236,6 +280,7 @@ def validate_and_deploy_arm_template( # Wait for the deployment to complete and get the outputs deployment: DeploymentExtended = poller.result() + logger.debug("Finished deploying") if deployment.properties is not None: depl_props = deployment.properties diff --git a/src/aosm/azext_aosm/deploy/pre_deploy.py b/src/aosm/azext_aosm/deploy/pre_deploy.py index a4e332f5b34..f17edb7489f 100644 --- a/src/aosm/azext_aosm/deploy/pre_deploy.py +++ b/src/aosm/azext_aosm/deploy/pre_deploy.py @@ -269,6 +269,54 @@ def ensure_config_nfdg_exists( self.config.nfdg_name, self.config.location, ) + + def does_artifact_manifest_exist(self, + rg_name: str, + publisher_name: str, + store_name: str, + manifest_name: str + ) -> bool: + try: + self.api_clients.aosm_client.artifact_manifests.get( + resource_group_name=rg_name, + publisher_name=publisher_name, + artifact_store_name=store_name, + artifact_manifest_name=manifest_name + ) + logger.debug(f"Artifact manifest {manifest_name} exists") + return True + except azure_exceptions.ResourceNotFoundError: + logger.debug(f"Artifact manifest {manifest_name} does not exist") + return False + + def do_config_artifact_manifests_exist( + self, + ): + """ + Returns True if all required manifests exist, False otherwise + """ + acr_manny_exists: bool = self.does_artifact_manifest_exist( + rg_name=self.config.publisher_resource_group_name, + publisher_name=self.config.publisher_name, + store_name=self.config.acr_artifact_store_name, + manifest_name=self.config.acr_manifest_name + ) + + if isinstance(self.config, VNFConfiguration): + sa_manny_exists: bool = self.does_artifact_manifest_exist( + rg_name=self.config.publisher_resource_group_name, + publisher_name=self.config.publisher_name, + store_name=self.config.blob_artifact_store_name, + manifest_name=self.config.sa_manifest_name + ) + if acr_manny_exists and sa_manny_exists: + return True + elif acr_manny_exists or sa_manny_exists: + raise AzCLIError("Only one artifact manifest exists. Cannot proceed. Please delete the NFDV using `az aosm definition delete` and start the publish again from scratch.") + else: + return False + + return acr_manny_exists def ensure_nsdg_exists( self, diff --git a/src/aosm/azext_aosm/generate_nfd/templates/vnfartifactmanifests.bicep b/src/aosm/azext_aosm/generate_nfd/templates/vnfartifactmanifests.bicep new file mode 100644 index 00000000000..20e7d5e2e2b --- /dev/null +++ b/src/aosm/azext_aosm/generate_nfd/templates/vnfartifactmanifests.bicep @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. + +// This file creates an NF definition for a VNF +param location string = resourceGroup().location +@description('Name of an existing publisher, expected to be in the resource group where you deploy the template') +param publisherName string +@description('Name of an existing ACR-backed Artifact Store, deployed under the publisher.') +param acrArtifactStoreName string +@description('Name of an existing Storage Account-backed Artifact Store, deployed under the publisher.') +param saArtifactStoreName string +@description('Name of the manifest to deploy for the ACR-backed Artifact Store') +param acrManifestName string +@description('Name of the manifest to deploy for the Storage Account-backed Artifact Store') +param saManifestName string +@description('The name under which to store the VHD') +param vhdName string +@description('The version that you want to name the NFM VHD artifact, in format A-B-C. e.g. 6-13-0') +param vhdVersion string +@description('The name under which to store the ARM template') +param armTemplateName string +@description('The version that you want to name the NFM template artifact, in format A.B.C. e.g. 6.13.0. If testing for development, you can use any numbers you like.') +param armTemplateVersion string + +// Created by the az aosm definition publish command before the template is deployed +resource publisher 'Microsoft.HybridNetwork/publishers@2022-09-01-preview' existing = { + name: publisherName + scope: resourceGroup() +} + +// Created by the az aosm definition publish command before the template is deployed +resource acrArtifactStore 'Microsoft.HybridNetwork/publishers/artifactStores@2022-09-01-preview' existing = { + parent: publisher + name: acrArtifactStoreName +} + +// Created by the az aosm definition publish command before the template is deployed +resource saArtifactStore 'Microsoft.HybridNetwork/publishers/artifactStores@2022-09-01-preview' existing = { + parent: publisher + name: saArtifactStoreName +} + +resource saArtifactManifest 'Microsoft.Hybridnetwork/publishers/artifactStores/artifactManifests@2022-09-01-preview' = { + parent: saArtifactStore + name: saManifestName + location: location + properties: { + artifacts: [ + { + artifactName: '${vhdName}' + artifactType: 'VhdImageFile' + artifactVersion: vhdVersion + } + ] + } +} + +resource acrArtifactManifest 'Microsoft.Hybridnetwork/publishers/artifactStores/artifactManifests@2022-09-01-preview' = { + parent: acrArtifactStore + name: acrManifestName + location: location + properties: { + artifacts: [ + { + artifactName: '${armTemplateName}' + artifactType: 'ArmTemplate' + artifactVersion: armTemplateVersion + } + ] + } +} diff --git a/src/aosm/azext_aosm/generate_nfd/templates/vnfdefinition.bicep b/src/aosm/azext_aosm/generate_nfd/templates/vnfdefinition.bicep index aafdd474de5..87f3b93e15f 100644 --- a/src/aosm/azext_aosm/generate_nfd/templates/vnfdefinition.bicep +++ b/src/aosm/azext_aosm/generate_nfd/templates/vnfdefinition.bicep @@ -8,22 +8,14 @@ param publisherName string param acrArtifactStoreName string @description('Name of an existing Storage Account-backed Artifact Store, deployed under the publisher.') param saArtifactStoreName string -@description('Name of the manifest to deploy for the ACR-backed Artifact Store') -param acrManifestName string -@description('Name of the manifest to deploy for the Storage Account-backed Artifact Store') -param saManifestName string @description('Name of Network Function. Used predominantly as a prefix for other variable names') param nfName string @description('Name of an existing Network Function Definition Group') param nfDefinitionGroup string @description('The version of the NFDV you want to deploy, in format A-B-C') param nfDefinitionVersion string -@description('The name under which to store the VHD') -param vhdName string @description('The version that you want to name the NFM VHD artifact, in format A-B-C. e.g. 6-13-0') param vhdVersion string -@description('The name under which to store the ARM template') -param armTemplateName string @description('The version that you want to name the NFM template artifact, in format A.B.C. e.g. 6.13.0. If testing for development, you can use any numbers you like.') param armTemplateVersion string @@ -51,36 +43,6 @@ resource nfdg 'Microsoft.Hybridnetwork/publishers/networkfunctiondefinitiongroup name: nfDefinitionGroup } -resource saArtifactManifest 'Microsoft.Hybridnetwork/publishers/artifactStores/artifactManifests@2022-09-01-preview' = { - parent: saArtifactStore - name: saManifestName - location: location - properties: { - artifacts: [ - { - artifactName: '${vhdName}' - artifactType: 'VhdImageFile' - artifactVersion: vhdVersion - } - ] - } -} - -resource acrArtifactManifest 'Microsoft.Hybridnetwork/publishers/artifactStores/artifactManifests@2022-09-01-preview' = { - parent: acrArtifactStore - name: acrManifestName - location: location - properties: { - artifacts: [ - { - artifactName: '${armTemplateName}' - artifactType: 'ArmTemplate' - artifactVersion: armTemplateVersion - } - ] - } -} - resource nfdv 'Microsoft.Hybridnetwork/publishers/networkfunctiondefinitiongroups/networkfunctiondefinitionversions@2022-09-01-preview' = { parent: nfdg name: nfDefinitionVersion diff --git a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py index 5547cd1aa16..5f179d5207f 100644 --- a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py @@ -21,6 +21,7 @@ from azext_aosm._constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, VNF_DEFINITION_OUTPUT_BICEP_PREFIX, + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE ) @@ -41,11 +42,13 @@ def __init__(self, config: VNFConfiguration): ) self.config = config self.bicep_template_name = VNF_DEFINITION_BICEP_SOURCE_TEMPLATE + self.manifest_template_name = VNF_MANIFEST_BICEP_SOURCE_TEMPLATE self.arm_template_path = self.config.arm_template.file_path - self.folder_name = f"{VNF_DEFINITION_OUTPUT_BICEP_PREFIX}{Path(str(self.arm_template_path)).stem}" + self.folder_name = self.config.build_output_folder_name self._bicep_path = os.path.join(self.folder_name, self.bicep_template_name) + self._manifest_path = os.path.join(self.folder_name, self.manifest_template_name) def generate_nfd(self) -> None: """Generate a VNF NFD which comprises an group, an Artifact Manifest and a NFDV.""" @@ -82,6 +85,14 @@ def bicep_path(self) -> Optional[str]: return self._bicep_path return None + + @property + def manifest_path(self) -> Optional[str]: + """Returns the path to the bicep file for the NFD if it has been created.""" + if os.path.exists(self._manifest_path): + return self._manifest_path + + return None def _create_nfd_folder(self) -> None: """ @@ -205,5 +216,7 @@ def copy_bicep(self) -> None: code_dir = os.path.dirname(__file__) bicep_path = os.path.join(code_dir, "templates", self.bicep_template_name) + manifest_path = os.path.join(code_dir, "templates", self.manifest_template_name) shutil.copy(bicep_path, self.folder_name) + shutil.copy(manifest_path, self.folder_name) From c741773e5a6c3743a4a1098dcf09b7b0e1369f6f Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 15:41:56 +0100 Subject: [PATCH 02/13] style --- src/aosm/azext_aosm/_configuration.py | 55 ++++++++----------- src/aosm/azext_aosm/_help.py | 1 - src/aosm/azext_aosm/_params.py | 4 +- src/aosm/azext_aosm/commands.py | 3 +- src/aosm/azext_aosm/custom.py | 49 ++++++++--------- src/aosm/azext_aosm/deploy/artifact.py | 10 +++- src/aosm/azext_aosm/deploy/deploy_with_arm.py | 51 +++++++++-------- src/aosm/azext_aosm/deploy/pre_deploy.py | 27 ++++----- .../generate_nfd/vnf_bicep_nfd_generator.py | 11 ++-- 9 files changed, 105 insertions(+), 106 deletions(-) diff --git a/src/aosm/azext_aosm/_configuration.py b/src/aosm/azext_aosm/_configuration.py index d87b391f4eb..75df986414a 100644 --- a/src/aosm/azext_aosm/_configuration.py +++ b/src/aosm/azext_aosm/_configuration.py @@ -2,19 +2,14 @@ from typing import Dict, Optional, Any from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError from pathlib import Path -from azext_aosm._constants import ( - VNF_DEFINITION_OUTPUT_BICEP_PREFIX, - VNF, - CNF, - NSD -) - -DESCRIPTION_MAP: Dict[str,str] = { +from azext_aosm._constants import VNF_DEFINITION_OUTPUT_BICEP_PREFIX, VNF, CNF, NSD + +DESCRIPTION_MAP: Dict[str, str] = { "publisher_name": "Name of the Publisher resource you want you definition published to", "publisher_resource_group_name": "Resource group the Publisher resource is in or you want it to be in", "nf_name": "Name of NF definition", "version": "Version of the NF definition", - "acr_artifact_store_name":"Name of the ACR Artifact Store resource", + "acr_artifact_store_name": "Name of the ACR Artifact Store resource", "location": "Azure location of the resources", "blob_artifact_store_name": "Name of the storage account Artifact Store resource", "artifact_name": "Name of the artifact", @@ -23,7 +18,7 @@ "artifact_version": ( "Version of the artifact. For VHDs this must be in format A-B-C. " "For ARM templates this must be in format A.B.C" - ) + ), } @@ -32,19 +27,17 @@ class ArtifactConfig: artifact_name: str = DESCRIPTION_MAP["artifact_name"] # artifact.py checks for the presence of the default descriptions, change there if # you change the descriptions. - file_path: Optional[ - str - ] = DESCRIPTION_MAP["file_path"] - blob_sas_url: Optional[ - str - ] = DESCRIPTION_MAP["blob_sas_url"] + file_path: Optional[str] = DESCRIPTION_MAP["file_path"] + blob_sas_url: Optional[str] = DESCRIPTION_MAP["blob_sas_url"] version: str = DESCRIPTION_MAP["artifact_version"] @dataclass class Configuration: publisher_name: str = DESCRIPTION_MAP["publisher_name"] - publisher_resource_group_name: str = DESCRIPTION_MAP["publisher_resource_group_name"] + publisher_resource_group_name: str = DESCRIPTION_MAP[ + "publisher_resource_group_name" + ] nf_name: str = DESCRIPTION_MAP["nf_name"] version: str = DESCRIPTION_MAP["version"] acr_artifact_store_name: str = DESCRIPTION_MAP["acr_artifact_store_name"] @@ -66,25 +59,24 @@ class VNFConfiguration(Configuration): blob_artifact_store_name: str = DESCRIPTION_MAP["blob_artifact_store_name"] arm_template: Any = ArtifactConfig() vhd: Any = ArtifactConfig() - + def __post_init__(self): """ Cope with deserializing subclasses from dicts to ArtifactConfig. - + Used when creating VNFConfiguration object from a loaded json config file. """ if isinstance(self.arm_template, dict): self.arm_template = ArtifactConfig(**self.arm_template) - + if isinstance(self.vhd, dict): self.vhd = ArtifactConfig(**self.vhd) - @property def sa_manifest_name(self) -> str: """Return the Storage account manifest name from the NFD name.""" return f"{self.nf_name}-sa-manifest-{self.version.replace('.', '-')}" - + @property def build_output_folder_name(self) -> str: """Return the local folder for generating the bicep template to.""" @@ -94,8 +86,9 @@ def build_output_folder_name(self) -> str: ) -def get_configuration(definition_type: str, config_as_dict: Optional[Dict[Any,Any]]=None) -> Configuration: - +def get_configuration( + definition_type: str, config_as_dict: Optional[Dict[Any, Any]] = None +) -> Configuration: if config_as_dict is None: config_as_dict = {} @@ -129,17 +122,17 @@ def validate_configuration(config: Configuration) -> None: raise ValidationError( "Config validation error. VHD artifact version should be in format A-B-C" ) - if ( - "." not in config.arm_template.version - or "-" in config.arm_template.version - ): + if "." not in config.arm_template.version or "-" in config.arm_template.version: raise ValidationError( "Config validation error. ARM template artifact version should be in format A.B.C" ) - if not ((config.vhd.file_path or config.vhd.blob_sas_url) or ( - config.vhd.file_path == DESCRIPTION_MAP["file_path"] and - config.vhd.blob_sas_url == DESCRIPTION_MAP["blob_sas_url"]) + if not ( + (config.vhd.file_path or config.vhd.blob_sas_url) + or ( + config.vhd.file_path == DESCRIPTION_MAP["file_path"] + and config.vhd.blob_sas_url == DESCRIPTION_MAP["blob_sas_url"] + ) ): raise ValidationError( "Config validation error. VHD config must have either a local filepath or a blob SAS URL" diff --git a/src/aosm/azext_aosm/_help.py b/src/aosm/azext_aosm/_help.py index df276d4f8bd..2a9a3013fd9 100644 --- a/src/aosm/azext_aosm/_help.py +++ b/src/aosm/azext_aosm/_help.py @@ -43,7 +43,6 @@ """ - helps[ "aosm definition delete" ] = """ diff --git a/src/aosm/azext_aosm/_params.py b/src/aosm/azext_aosm/_params.py index 622f4998c76..e3fb517212b 100644 --- a/src/aosm/azext_aosm/_params.py +++ b/src/aosm/azext_aosm/_params.py @@ -6,7 +6,8 @@ from argcomplete.completers import FilesCompleter from azure.cli.core import AzCommandsLoader -#from knack.arguments import CLIArgumentType + +# from knack.arguments import CLIArgumentType from ._constants import VNF, CNF, NSD @@ -56,7 +57,6 @@ def load_arguments(self: AzCommandsLoader, _): completer=FilesCompleter(allowednames="*.json"), help="Optional path to a parameters file for the bicep definition file. Use to override publish of the built definition and config with alternative parameters.", ) - with self.argument_context("aosm generate-config") as c: c.argument( diff --git a/src/aosm/azext_aosm/commands.py b/src/aosm/azext_aosm/commands.py index 66b42311cbf..c906ca6947e 100644 --- a/src/aosm/azext_aosm/commands.py +++ b/src/aosm/azext_aosm/commands.py @@ -5,7 +5,8 @@ # pylint: disable=line-too-long from azure.cli.core import AzCommandsLoader -#from azure.cli.core.commands import CliCommandType + +# from azure.cli.core.commands import CliCommandType from azext_aosm._client_factory import cf_aosm diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index c18facc45b7..51fb7a55115 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -16,11 +16,7 @@ from azext_aosm.util.management_clients import ApiClientsAndCaches from .vendored_sdks import HybridNetworkManagementClient from ._client_factory import cf_resources -from ._configuration import ( - get_configuration, - validate_configuration, - Configuration -) +from ._configuration import get_configuration, validate_configuration, Configuration logger = get_logger(__name__) @@ -33,7 +29,8 @@ def build_definition( config_file: str, publish=False, ): - """Build and optionally publish a definition + """ + Build and optionally publish a definition. :param cmd: _description_ :type cmd: _type_ @@ -51,7 +48,7 @@ def build_definition( ) config = _get_config_from_file(config_file, definition_type) - + # Generate the NFD/NSD and the artifact manifest. _generate_nfd(definition_type=definition_type, config=config) # Write the ARM/bicep template if that's what we are doing @@ -65,21 +62,19 @@ def build_definition( print("TODO - cannot publish CNF or NSD yet.") -def generate_definition_config(definition_type: str, output_file: str="input.json"): +def generate_definition_config(definition_type: str, output_file: str = "input.json"): config = get_configuration(definition_type) config_as_dict = json.dumps(asdict(config), indent=4) with open(output_file, "w", encoding="utf-8") as f: f.write(config_as_dict) - print( - f"Empty definition configuration has been written to {output_file}" - ) - logger.info( - f"Empty definition configuration has been written to {output_file}" - ) - + print(f"Empty definition configuration has been written to {output_file}") + logger.info(f"Empty definition configuration has been written to {output_file}") + + def _get_config_from_file(config_file: str, definition_type: str) -> Configuration: - """Read input config file JSON and turn it into a Configuration object. + """ + Read input config file JSON and turn it into a Configuration object. :param config_file: path to the file :param definition_type: VNF, CNF or NSD @@ -113,30 +108,31 @@ def _generate_nfd(definition_type, config): ) nfd_generator.generate_nfd() - + + def publish_definition( cmd, client: HybridNetworkManagementClient, definition_type, config_file, bicep_file: Optional[str] = None, - parameters_json_file: Optional[str] = None + parameters_json_file: Optional[str] = None, ): - """_summary_ + """ + _summary_ - :param cmd: - :param client: + :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 bicep_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 + :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 - """ print("Publishing definition.") api_clients = ApiClientsAndCaches( @@ -145,8 +141,9 @@ def publish_definition( config = _get_config_from_file(config_file, definition_type) if definition_type == VNF: deployer = DeployerViaArm(api_clients, config=config) - deployer.deploy_vnfd_from_bicep(bicep_path=bicep_file, - parameters_json_file=parameters_json_file) + deployer.deploy_vnfd_from_bicep( + bicep_path=bicep_file, parameters_json_file=parameters_json_file + ) def delete_published_definition( diff --git a/src/aosm/azext_aosm/deploy/artifact.py b/src/aosm/azext_aosm/deploy/artifact.py index bbb647182be..b8b0287b117 100644 --- a/src/aosm/azext_aosm/deploy/artifact.py +++ b/src/aosm/azext_aosm/deploy/artifact.py @@ -43,7 +43,10 @@ def _upload_to_acr(self, artifact_config: ArtifactConfig) -> None: # If not included in config, the file path value will be the description of # the field. - if artifact_config.file_path and not artifact_config.file_path == DESCRIPTION_MAP["file_path"]: + if ( + artifact_config.file_path + and not artifact_config.file_path == DESCRIPTION_MAP["file_path"] + ): target = f"{self.artifact_client.remote.hostname.replace('https://', '')}/{self.artifact_name}:{self.artifact_version}" logger.debug(f"Uploading {artifact_config.file_path} to {target}") self.artifact_client.push( @@ -64,7 +67,10 @@ def _upload_to_storage_account(self, artifact_config: ArtifactConfig) -> None: assert type(self.artifact_client) == BlobClient # If the file path is given, upload the artifact, else, copy it from an existing blob. - if artifact_config.file_path and not artifact_config.file_path == DESCRIPTION_MAP["file_path"]: + if ( + artifact_config.file_path + and not artifact_config.file_path == DESCRIPTION_MAP["file_path"] + ): logger.info("Upload to blob store") with open(artifact_config.file_path, "rb") as artifact: self.artifact_client.upload_blob(artifact, overwrite=True) diff --git a/src/aosm/azext_aosm/deploy/deploy_with_arm.py b/src/aosm/azext_aosm/deploy/deploy_with_arm.py index 5748b8cf96f..553020b7d6e 100644 --- a/src/aosm/azext_aosm/deploy/deploy_with_arm.py +++ b/src/aosm/azext_aosm/deploy/deploy_with_arm.py @@ -19,7 +19,7 @@ from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm._constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, - VNF_MANIFEST_BICEP_SOURCE_TEMPLATE + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, ) @@ -49,10 +49,11 @@ def __init__( self.config = config self.pre_deployer = PreDeployerViaSDK(apiClientsAndCaches, self.config) - def deploy_vnfd_from_bicep(self, - bicep_path: Optional[str] = None, - parameters_json_file: Optional[str] = None - ) -> None: + def deploy_vnfd_from_bicep( + self, + bicep_path: Optional[str] = None, + parameters_json_file: Optional[str] = None, + ) -> None: """ Deploy the bicep template defining the VNFD. @@ -66,19 +67,21 @@ def deploy_vnfd_from_bicep(self, if not bicep_path: # User has not passed in a bicep template, so we are deploying the default # one produced from building the NFDV using this CLI - bicep_path = os.path.join(self.config.build_output_folder_name, - VNF_DEFINITION_BICEP_SOURCE_TEMPLATE) - + bicep_path = os.path.join( + self.config.build_output_folder_name, + VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, + ) + if parameters_json_file: message: str = f"Use parameters from file {parameters_json_file}" logger.info(message) print(message) with open(parameters_json_file, "r", encoding="utf-8") as f: parameters = json.loads(f.read()) - + else: # User has not passed in parameters file, so we use the parameters required - # from config for the default bicep template produced from building the + # from config for the default bicep template produced from building the # NFDV using this CLI logger.debug("Create parameters for default NFDV template.") parameters = self.construct_vnfd_parameters() @@ -90,22 +93,25 @@ def deploy_vnfd_from_bicep(self, if deploy_manifest_template: print(f"Deploy bicep template for Artifact manifests") logger.debug("Deploy manifest bicep") - manifest_bicep_path = os.path.join(self.config.build_output_folder_name, - VNF_MANIFEST_BICEP_SOURCE_TEMPLATE) + manifest_bicep_path = os.path.join( + self.config.build_output_folder_name, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE + ) manifest_params = self.construct_manifest_parameters() self.deploy_bicep_template(manifest_bicep_path, manifest_params) else: - print(f"Artifact manifests exist for NFD {self.config.nf_name} " - f"version {self.config.version}") - message = (f"Deploy bicep template for NFD {self.config.nf_name} version {self.config.version} " + print( + f"Artifact manifests exist for NFD {self.config.nf_name} " + f"version {self.config.version}" + ) + message = ( + f"Deploy bicep template for NFD {self.config.nf_name} version {self.config.version} " f"into {self.config.publisher_resource_group_name} under publisher " - f"{self.config.publisher_name}") + f"{self.config.publisher_name}" + ) print(message) logger.info(message) self.deploy_bicep_template(bicep_path, parameters) - print( - f"Deployed NFD {self.config.nf_name} version {self.config.version}." - ) + print(f"Deployed NFD {self.config.nf_name} version {self.config.version}.") storage_account_manifest = ArtifactManifestOperator( self.config, @@ -133,8 +139,7 @@ def vnfd_predeploy(self) -> bool: """ All the predeploy steps for a VNF. Create publisher, artifact stores and NFDG. - VNF specific - return True if artifact manifest already exists, False otherwise + VNF specific return True if artifact manifest already exists, False otherwise """ logger.debug("Ensure all required resources exist") self.pre_deployer.ensure_config_resource_group_exists() @@ -161,7 +166,7 @@ def construct_vnfd_parameters(self) -> Dict[str, Any]: "vhdVersion": {"value": self.config.vhd.version}, "armTemplateVersion": {"value": self.config.arm_template.version}, } - + def construct_manifest_parameters(self) -> Dict[str, Any]: """ Create the parmeters dictionary for vnfdefinitions.bicep. VNF specific. @@ -179,7 +184,7 @@ def construct_manifest_parameters(self) -> Dict[str, Any]: "vhdVersion": {"value": self.config.vhd.version}, "armTemplateName": {"value": self.config.arm_template.artifact_name}, "armTemplateVersion": {"value": self.config.arm_template.version}, - } + } def deploy_bicep_template( self, bicep_template_path: str, parameters: Dict[Any, Any] diff --git a/src/aosm/azext_aosm/deploy/pre_deploy.py b/src/aosm/azext_aosm/deploy/pre_deploy.py index f17edb7489f..5f4e7e6f280 100644 --- a/src/aosm/azext_aosm/deploy/pre_deploy.py +++ b/src/aosm/azext_aosm/deploy/pre_deploy.py @@ -269,37 +269,32 @@ def ensure_config_nfdg_exists( self.config.nfdg_name, self.config.location, ) - - def does_artifact_manifest_exist(self, - rg_name: str, - publisher_name: str, - store_name: str, - manifest_name: str - ) -> bool: + + def does_artifact_manifest_exist( + self, rg_name: str, publisher_name: str, store_name: str, manifest_name: str + ) -> bool: try: self.api_clients.aosm_client.artifact_manifests.get( resource_group_name=rg_name, publisher_name=publisher_name, artifact_store_name=store_name, - artifact_manifest_name=manifest_name + artifact_manifest_name=manifest_name, ) logger.debug(f"Artifact manifest {manifest_name} exists") return True except azure_exceptions.ResourceNotFoundError: logger.debug(f"Artifact manifest {manifest_name} does not exist") return False - + def do_config_artifact_manifests_exist( self, ): - """ - Returns True if all required manifests exist, False otherwise - """ + """Returns True if all required manifests exist, False otherwise.""" acr_manny_exists: bool = self.does_artifact_manifest_exist( rg_name=self.config.publisher_resource_group_name, publisher_name=self.config.publisher_name, store_name=self.config.acr_artifact_store_name, - manifest_name=self.config.acr_manifest_name + manifest_name=self.config.acr_manifest_name, ) if isinstance(self.config, VNFConfiguration): @@ -307,12 +302,14 @@ def do_config_artifact_manifests_exist( rg_name=self.config.publisher_resource_group_name, publisher_name=self.config.publisher_name, store_name=self.config.blob_artifact_store_name, - manifest_name=self.config.sa_manifest_name + manifest_name=self.config.sa_manifest_name, ) if acr_manny_exists and sa_manny_exists: return True elif acr_manny_exists or sa_manny_exists: - raise AzCLIError("Only one artifact manifest exists. Cannot proceed. Please delete the NFDV using `az aosm definition delete` and start the publish again from scratch.") + raise AzCLIError( + "Only one artifact manifest exists. Cannot proceed. Please delete the NFDV using `az aosm definition delete` and start the publish again from scratch." + ) else: return False diff --git a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py index 5f179d5207f..31f7bc7061b 100644 --- a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py @@ -20,8 +20,7 @@ ) from azext_aosm._constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, - VNF_DEFINITION_OUTPUT_BICEP_PREFIX, - VNF_MANIFEST_BICEP_SOURCE_TEMPLATE + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, ) @@ -48,7 +47,9 @@ def __init__(self, config: VNFConfiguration): self.folder_name = self.config.build_output_folder_name self._bicep_path = os.path.join(self.folder_name, self.bicep_template_name) - self._manifest_path = os.path.join(self.folder_name, self.manifest_template_name) + self._manifest_path = os.path.join( + self.folder_name, self.manifest_template_name + ) def generate_nfd(self) -> None: """Generate a VNF NFD which comprises an group, an Artifact Manifest and a NFDV.""" @@ -85,14 +86,14 @@ def bicep_path(self) -> Optional[str]: return self._bicep_path return None - + @property def manifest_path(self) -> Optional[str]: """Returns the path to the bicep file for the NFD if it has been created.""" if os.path.exists(self._manifest_path): return self._manifest_path - return None + return None def _create_nfd_folder(self) -> None: """ From a956ce6cc6d80dabdcd886ad8606f3b45d0a7edb Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 16:02:49 +0100 Subject: [PATCH 03/13] renames --- src/aosm/azext_aosm/_params.py | 2 +- .../{_client_factory.py => client_factory.py} | 0 src/aosm/azext_aosm/commands.py | 2 +- .../{_configuration.py => configuration.py} | 2 +- src/aosm/azext_aosm/custom.py | 14 +- src/aosm/azext_aosm/delete/delete.py | 8 +- src/aosm/azext_aosm/deploy/artifact.py | 2 +- .../azext_aosm/deploy/artifact_manifest.py | 6 +- src/aosm/azext_aosm/deploy/deploy_with_arm.py | 12 +- src/aosm/azext_aosm/deploy/pre_deploy.py | 12 +- .../generate_nfd/nfd_generator_base.py | 11 +- .../generate_nfd/vnf_bicep_nfd_generator.py | 39 ++---- .../publisher_resources.py | 31 ----- .../{_constants.py => util/constants.py} | 0 .../azext_aosm/util/management_clients.py | 125 +----------------- .../{_validators.py => validators.py} | 0 .../_hybrid_network_management_client.py | 2 +- .../aio/_hybrid_network_management_client.py | 2 +- .../vendored_sdks/aio/operations/__init__.py | 4 +- .../vendored_sdks/operations/__init__.py | 4 +- 20 files changed, 54 insertions(+), 224 deletions(-) rename src/aosm/azext_aosm/{_client_factory.py => client_factory.py} (100%) rename src/aosm/azext_aosm/{_configuration.py => configuration.py} (98%) delete mode 100644 src/aosm/azext_aosm/publisher_resources/publisher_resources.py rename src/aosm/azext_aosm/{_constants.py => util/constants.py} (100%) rename src/aosm/azext_aosm/{_validators.py => validators.py} (100%) diff --git a/src/aosm/azext_aosm/_params.py b/src/aosm/azext_aosm/_params.py index e3fb517212b..8fd8fd47cfd 100644 --- a/src/aosm/azext_aosm/_params.py +++ b/src/aosm/azext_aosm/_params.py @@ -8,7 +8,7 @@ from azure.cli.core import AzCommandsLoader # from knack.arguments import CLIArgumentType -from ._constants import VNF, CNF, NSD +from .util.constants import VNF, CNF, NSD def load_arguments(self: AzCommandsLoader, _): diff --git a/src/aosm/azext_aosm/_client_factory.py b/src/aosm/azext_aosm/client_factory.py similarity index 100% rename from src/aosm/azext_aosm/_client_factory.py rename to src/aosm/azext_aosm/client_factory.py diff --git a/src/aosm/azext_aosm/commands.py b/src/aosm/azext_aosm/commands.py index c906ca6947e..0f65c359929 100644 --- a/src/aosm/azext_aosm/commands.py +++ b/src/aosm/azext_aosm/commands.py @@ -7,7 +7,7 @@ from azure.cli.core import AzCommandsLoader # from azure.cli.core.commands import CliCommandType -from azext_aosm._client_factory import cf_aosm +from azext_aosm.client_factory import cf_aosm def load_command_table(self: AzCommandsLoader, _): diff --git a/src/aosm/azext_aosm/_configuration.py b/src/aosm/azext_aosm/configuration.py similarity index 98% rename from src/aosm/azext_aosm/_configuration.py rename to src/aosm/azext_aosm/configuration.py index 75df986414a..b9a93efa6a2 100644 --- a/src/aosm/azext_aosm/_configuration.py +++ b/src/aosm/azext_aosm/configuration.py @@ -2,7 +2,7 @@ from typing import Dict, Optional, Any from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError from pathlib import Path -from azext_aosm._constants import VNF_DEFINITION_OUTPUT_BICEP_PREFIX, VNF, CNF, NSD +from azext_aosm.util.constants import VNF_DEFINITION_OUTPUT_BICEP_PREFIX, VNF, CNF, NSD DESCRIPTION_MAP: Dict[str, str] = { "publisher_name": "Name of the Publisher resource you want you definition published to", diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index 51fb7a55115..feccdfdd1a5 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -12,11 +12,11 @@ from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator from azext_aosm.generate_nfd.vnf_bicep_nfd_generator import VnfBicepNfdGenerator from azext_aosm.deploy.deploy_with_arm import DeployerViaArm -from azext_aosm._constants import VNF, CNF, NSD -from azext_aosm.util.management_clients import ApiClientsAndCaches +from azext_aosm.util.constants import VNF, CNF, NSD +from azext_aosm.util.management_clients import ApiClients from .vendored_sdks import HybridNetworkManagementClient -from ._client_factory import cf_resources -from ._configuration import get_configuration, validate_configuration, Configuration +from .client_factory import cf_resources +from configuration import get_configuration, validate_configuration, Configuration logger = get_logger(__name__) @@ -43,7 +43,7 @@ def build_definition( :param publish: _description_, defaults to False :type publish: bool, optional """ - api_clients = ApiClientsAndCaches( + api_clients = ApiClients( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) ) @@ -135,7 +135,7 @@ def publish_definition( for the bicep file """ print("Publishing definition.") - api_clients = ApiClientsAndCaches( + api_clients = ApiClients( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) ) config = _get_config_from_file(config_file, definition_type) @@ -164,7 +164,7 @@ def delete_published_definition( """ config = _get_config_from_file(config_file, definition_type) - api_clients = ApiClientsAndCaches( + api_clients = ApiClients( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) ) from azext_aosm.delete.delete import ResourceDeleter diff --git a/src/aosm/azext_aosm/delete/delete.py b/src/aosm/azext_aosm/delete/delete.py index 45ce6e3887c..1d83ab489d6 100644 --- a/src/aosm/azext_aosm/delete/delete.py +++ b/src/aosm/azext_aosm/delete/delete.py @@ -11,8 +11,8 @@ Provider, ) -from azext_aosm.util.management_clients import ApiClientsAndCaches -from azext_aosm._configuration import Configuration, VNFConfiguration +from azext_aosm.util.management_clients import ApiClients +from azext_aosm.configuration import Configuration, VNFConfiguration from azext_aosm.util.utils import input_ack @@ -22,7 +22,7 @@ class ResourceDeleter: def __init__( self, - apiClientsAndCaches: ApiClientsAndCaches, + ApiClients: ApiClients, config: Configuration, ) -> None: """ @@ -34,7 +34,7 @@ def __init__( :type resource_client: ResourceManagementClient """ logger.debug("Create ARM/Bicep Deployer") - self.api_clients = apiClientsAndCaches + self.api_clients = ApiClients self.config = config def delete_vnf(self, all: bool = False): diff --git a/src/aosm/azext_aosm/deploy/artifact.py b/src/aosm/azext_aosm/deploy/artifact.py index b8b0287b117..b457a672c8e 100644 --- a/src/aosm/azext_aosm/deploy/artifact.py +++ b/src/aosm/azext_aosm/deploy/artifact.py @@ -7,7 +7,7 @@ from typing import Union from azure.storage.blob import BlobClient -from azext_aosm._configuration import ArtifactConfig, DESCRIPTION_MAP +from azext_aosm.configuration import ArtifactConfig, DESCRIPTION_MAP from oras.client import OrasClient logger = get_logger(__name__) diff --git a/src/aosm/azext_aosm/deploy/artifact_manifest.py b/src/aosm/azext_aosm/deploy/artifact_manifest.py index 6dc3c31ea0d..27ac2f003da 100644 --- a/src/aosm/azext_aosm/deploy/artifact_manifest.py +++ b/src/aosm/azext_aosm/deploy/artifact_manifest.py @@ -10,10 +10,10 @@ from azext_aosm.deploy.artifact import Artifact from azure.storage.blob import BlobClient from oras.client import OrasClient -from azext_aosm._configuration import Configuration, VNFConfiguration +from azext_aosm.configuration import Configuration, VNFConfiguration from azext_aosm.vendored_sdks.models import ArtifactAccessCredential, ArtifactManifest -from azext_aosm.util.management_clients import ApiClientsAndCaches +from azext_aosm.util.management_clients import ApiClients logger = get_logger(__name__) @@ -24,7 +24,7 @@ class ArtifactManifestOperator: def __init__( self, config: Configuration, - api_clients: ApiClientsAndCaches, + api_clients: ApiClients, store_name: str, manifest_name: str, ) -> None: diff --git a/src/aosm/azext_aosm/deploy/deploy_with_arm.py b/src/aosm/azext_aosm/deploy/deploy_with_arm.py index 553020b7d6e..61dd1ff5346 100644 --- a/src/aosm/azext_aosm/deploy/deploy_with_arm.py +++ b/src/aosm/azext_aosm/deploy/deploy_with_arm.py @@ -11,13 +11,13 @@ from knack.log import get_logger from azext_aosm.deploy.artifact_manifest import ArtifactManifestOperator -from azext_aosm.util.management_clients import ApiClientsAndCaches +from azext_aosm.util.management_clients import ApiClients from azure.mgmt.resource.resources.v2021_04_01.models import DeploymentExtended from pathlib import Path from azext_aosm.deploy.pre_deploy import PreDeployerViaSDK -from azext_aosm._configuration import Configuration, VNFConfiguration -from azext_aosm._constants import ( +from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm.util.constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, ) @@ -33,7 +33,7 @@ class DeployerViaArm: # using the SDK def __init__( self, - apiClientsAndCaches: ApiClientsAndCaches, + api_clients: ApiClients, config: Configuration, ) -> None: """ @@ -45,9 +45,9 @@ def __init__( :type resource_client: ResourceManagementClient """ logger.debug("Create ARM/Bicep Deployer") - self.api_clients = apiClientsAndCaches + self.api_clients = api_clients self.config = config - self.pre_deployer = PreDeployerViaSDK(apiClientsAndCaches, self.config) + self.pre_deployer = PreDeployerViaSDK(api_clients, self.config) def deploy_vnfd_from_bicep( self, diff --git a/src/aosm/azext_aosm/deploy/pre_deploy.py b/src/aosm/azext_aosm/deploy/pre_deploy.py index 5f4e7e6f280..174d5ddadca 100644 --- a/src/aosm/azext_aosm/deploy/pre_deploy.py +++ b/src/aosm/azext_aosm/deploy/pre_deploy.py @@ -10,9 +10,7 @@ from azure.cli.core.azclierror import AzCLIError from azure.mgmt.resource.resources.v2022_09_01.models import ResourceGroup -from azure.mgmt.resource import ResourceManagementClient -from azext_aosm.util.management_clients import ApiClientsAndCaches -from azext_aosm.vendored_sdks import HybridNetworkManagementClient +from azext_aosm.util.management_clients import ApiClients from azext_aosm.vendored_sdks.models import ( ArtifactStore, ArtifactStoreType, @@ -20,8 +18,8 @@ NetworkServiceDesignGroup, Publisher, ) -from azext_aosm._configuration import Configuration, VNFConfiguration -from azext_aosm._constants import PROV_STATE_SUCCEEDED +from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm.util.constants import PROV_STATE_SUCCEEDED logger = get_logger(__name__) @@ -31,7 +29,7 @@ class PreDeployerViaSDK: def __init__( self, - apiClientsAndCaches: ApiClientsAndCaches, + api_clients: ApiClients, config: Configuration, ) -> None: """ @@ -43,7 +41,7 @@ def __init__( :type resource_client: ResourceManagementClient """ - self.api_clients = apiClientsAndCaches + self.api_clients = api_clients self.config = config def ensure_resource_group_exists(self, resource_group_name: str) -> None: diff --git a/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py b/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py index 2408972bc34..21c2f0c5bac 100644 --- a/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py +++ b/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py @@ -4,7 +4,6 @@ # -------------------------------------------------------------------------------------- """Contains a base class for generating NFDs.""" from knack.log import get_logger -from azext_aosm._configuration import Configuration logger = get_logger(__name__) @@ -15,17 +14,11 @@ class NFDGenerator: def __init__( self, - # config: Configuration ) -> None: """ - _summary_ - - :param definition_type: _description_ - :type definition_type: str - :param config: _description_ - :type config: Configuration + Superclass for NFD generators. The sub-classes do the actual work """ - # self.config = config + pass def generate_nfd(self) -> None: """No-op on base class.""" diff --git a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py index 31f7bc7061b..d27c9642a23 100644 --- a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py @@ -14,11 +14,8 @@ from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator -from azext_aosm._configuration import VNFConfiguration -from azext_aosm.publisher_resources.publisher_resources import ( - PublisherResourceGenerator, -) -from azext_aosm._constants import ( +from azext_aosm.configuration import VNFConfiguration +from azext_aosm.util.constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, ) @@ -29,15 +26,17 @@ class VnfBicepNfdGenerator(NFDGenerator): """ - _summary_ - - :param NFDGenerator: _description_ - :type NFDGenerator: _type_ + VNF NFD Generator. + + This takes a source ARM template and a config file, and outputs: + - A bicep file for the NFDV + - Parameters files that are used by the NFDV bicep file, these are the + deployParameters and the mapping profiles of those deploy parameters + - A bicep file for the Artifact manifests """ def __init__(self, config: VNFConfiguration): super(NFDGenerator, self).__init__( - # config=config, ) self.config = config self.bicep_template_name = VNF_DEFINITION_BICEP_SOURCE_TEMPLATE @@ -53,7 +52,6 @@ def __init__(self, config: VNFConfiguration): def generate_nfd(self) -> None: """Generate a VNF NFD which comprises an group, an Artifact Manifest and a NFDV.""" - # assert isinstance(self.config, VNFConfiguration) if self.bicep_path: print(f"Using the existing NFD bicep template {self.bicep_path}.") print( @@ -65,13 +63,8 @@ def generate_nfd(self) -> None: def write(self) -> None: """ Create a bicep template for an NFD from the ARM template for the VNF. - - :param arm_template_path: The path to the ARM template for deploying the VNF. - :param nf_name: The name of the NF. - - :return: Path to the bicep file. """ - logger.info("Generate NFD bicep template for %s", self.arm_template_path) + logger.info(f"Generate NFD bicep template for {self.arm_template_path}") print(f"Generate NFD bicep template for {self.arm_template_path}") self._create_nfd_folder() @@ -159,7 +152,7 @@ def write_deployment_parameters(self, folder_path: str) -> None: with open(deployment_parameters_path, "w") as _file: _file.write(json.dumps(deploy_parameters_full, indent=4)) - logger.debug("%s created", deployment_parameters_path) + logger.debug(f"{deployment_parameters_path} created") def write_template_parameters(self, folder_path: str) -> None: """ @@ -177,7 +170,7 @@ def write_template_parameters(self, folder_path: str) -> None: with open(template_parameters_path, "w") as _file: _file.write(json.dumps(template_parameters, indent=4)) - logger.debug("%s created", template_parameters_path) + logger.debug(f"{template_parameters_path} created") def write_vhd_parameters(self, folder_path: str) -> None: """ @@ -204,15 +197,11 @@ def write_vhd_parameters(self, folder_path: str) -> None: with open(vhd_parameters_path, "w", encoding="utf-8") as _file: _file.write(json.dumps(vhd_parameters, indent=4)) - logger.debug("%s created", vhd_parameters_path) + logger.debug(f"{vhd_parameters_path} created") def copy_bicep(self) -> None: """ - Copy the bicep template into place. - - :param folder_name: The name of the folder to copy the bicep template to. - - :returns: Path to the bicep file + Copy the bicep templates into the build output folder. """ code_dir = os.path.dirname(__file__) diff --git a/src/aosm/azext_aosm/publisher_resources/publisher_resources.py b/src/aosm/azext_aosm/publisher_resources/publisher_resources.py deleted file mode 100644 index c2a93b785db..00000000000 --- a/src/aosm/azext_aosm/publisher_resources/publisher_resources.py +++ /dev/null @@ -1,31 +0,0 @@ -# -------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT -# License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------- -"""Shared publisher resources.""" -from dataclasses import dataclass -from knack.log import get_logger -from azext_aosm.vendored_sdks.models import NetworkFunctionDefinitionGroup -from azext_aosm._configuration import Configuration - - -logger = get_logger(__name__) - - -@dataclass -class PublisherResourceGenerator: - """Class for generating publisher resources used by various other classes.""" - - config: Configuration - - def generate_nfd_group(self) -> NetworkFunctionDefinitionGroup: - """ - Generate a NFD group with location and description from config. - - :return: _description_ - :rtype: NetworkFunctionDefinitionGroup - """ - return NetworkFunctionDefinitionGroup( - location=self.config.location, - description=f"NFD Group for versions of NFDs for {self.config.nf_name}", - ) diff --git a/src/aosm/azext_aosm/_constants.py b/src/aosm/azext_aosm/util/constants.py similarity index 100% rename from src/aosm/azext_aosm/_constants.py rename to src/aosm/azext_aosm/util/constants.py diff --git a/src/aosm/azext_aosm/util/management_clients.py b/src/aosm/azext_aosm/util/management_clients.py index 541b6686fbb..01e90443a60 100644 --- a/src/aosm/azext_aosm/util/management_clients.py +++ b/src/aosm/azext_aosm/util/management_clients.py @@ -8,137 +8,18 @@ from dataclasses import dataclass from azure.mgmt.resource import ResourceManagementClient from azext_aosm.vendored_sdks import HybridNetworkManagementClient -from typing import Dict, Optional -from azure.mgmt.resource.resources.v2022_09_01.models import Provider logger = get_logger(__name__) -@dataclass -class ProviderInfo: - """Class to return Provider Info information.""" - - namespace: str - resource_type: str - - -class ApiClientsAndCaches: - """A cache for API Clients and API versions for various resources.""" +class ApiClients: + """A class for API Clients needed throughout.""" def __init__( self, aosm_client: HybridNetworkManagementClient, resource_client: ResourceManagementClient, ): + """Initialise with clients.""" self.aosm_client = aosm_client self.resource_client = resource_client - - # We need to find an Azure API version relevant to each resource type. This is - # used in resource finding. We just use the latest and cache these as they are - # expensive to query. - self.resource_type_api_versions_cache: Dict[str, str] = {} - self.providers_cache: Dict[str, Provider] = {} - - def find_latest_api_ver_for_resource_type( - self, resource_type: str - ) -> Optional[str]: - """ - Copied from virtutils. Turns out maybe not needed yet. Expect we will need - when we want to delete resources. - - Find the latest Azure API version for a given resource. - - We do this querying the Azure Providers API - - We just use the latest and cache these as they are expensive to query. - - param: resource_type: String in the format that the providers API uses e.g. - Microsoft.Compute/disks or Microsoft.Compute/virtualMachines/extensions - - Find the namespace and resource type in the format that the providers - API uses by splitting the resource type returned from list_by_resource_group - at the first forward-slash (/), - e.g. Microsoft.Compute/disks would give us namespace Microsoft.Compute and - provider resource type disks - whereas Microsoft.Compute/virtualMachines/extensions would give us - namespace Microsoft.Compute and provicer resource type - virtualMachines/extensions. This seems to match what the provider API - uses. - - We cache values as this can take a few seconds to return. - - :param resource: A resource, as returned from list_by_resource_group - :raises RuntimeError: If no provider found in Azure for this resource - :raises RuntimeError: If the resource type is an unexpected format - """ - logger.debug(f"Find API version for {resource_type}") - # We need to find an API version relevant to the resource. - if resource_type in self.resource_type_api_versions_cache.keys(): - # We have one cached, just return that - logger.debug("Return cached API version") - return self.resource_type_api_versions_cache.get(resource_type) - - # Start with e.g. Microsoft.Compute/disks (resource_type) - assert resource_type is not None - prov_info = self.get_provider_info(resource_type) - # We now have Microsoft.Compute and disks - if prov_info.namespace not in self.providers_cache.keys(): - # Get the provider e.g. Microsoft.Compute - logger.debug(f"Find provider {prov_info.namespace}") - try: - provider = self.resource_client.providers.get(prov_info.namespace) - except Exception as provEx: - raise RuntimeError( - f"Could not find provider {prov_info.namespace} required " - f"to query resource of type {resource_type}. Aborting" - ) from provEx - - self.providers_cache[prov_info.namespace] = provider - else: - # Resource type that we haven't found before but the provider is cached - # so use that. - provider = self.providers_cache[prov_info.namespace] - - # Iterate through the providers resource types and find the one - # we want, e.g. disks or virtualMachines/extensions - for res_type in provider.resource_types: - if res_type.resource_type == prov_info.resource_type: - # Find the latest API version and cache it - # The first index appears to always be the latest version - api_version = res_type.api_versions[0] - logger.debug(f"Use API version {api_version} for {resource_type}") - - assert resource_type is not None - self.resource_type_api_versions_cache[resource_type] = api_version - return api_version - - raise RuntimeError( - f"Azure API did not return an API version for {resource_type}." - f"Cannot query API version" - ) - - def get_provider_info(self, resource_type: str) -> ProviderInfo: - """ - Find provider namespace and resource_type, given a full resource_type. - - param: resource_type: String in the format that the providers API uses e.g. - Microsoft.Compute/disks or Microsoft.Compute/virtualMachines/extensions - - Find the namespace and resource type in the format that the providers - API uses by splitting the resource type returned from list_by_resource_group - at the first forward-slash (/), - e.g. Microsoft.Compute/disks would give us namespace Microsoft.Compute and - provider resource type disks - whereas Microsoft.Compute/virtualMachines/extensions would give us - namespace Microsoft.Compute and provicer resource type - virtualMachines/extensions. This seems to match what the provider API - uses. - """ - prov_namespace_type = resource_type.split("/", 1) - if len(prov_namespace_type) != 2: - raise RuntimeError( - f"Azure resource type {resource_type} " - "is in unexpected format. Cannot find API version." - ) - # print(f"Namespace {prov_namespace_type[0]} type {prov_namespace_type[1]}") - return ProviderInfo(prov_namespace_type[0], prov_namespace_type[1]) diff --git a/src/aosm/azext_aosm/_validators.py b/src/aosm/azext_aosm/validators.py similarity index 100% rename from src/aosm/azext_aosm/_validators.py rename to src/aosm/azext_aosm/validators.py diff --git a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py index fa704c623bc..b3e1f4fbb59 100644 --- a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py @@ -14,7 +14,7 @@ from azure.mgmt.core import ARMPipelineClient from . import models -from ._configuration import HybridNetworkManagementClientConfiguration +from configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py index 891ddcb7041..d1f51fc70f8 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py @@ -15,7 +15,7 @@ from azure.mgmt.core import AsyncARMPipelineClient from .. import models -from ._configuration import HybridNetworkManagementClientConfiguration +from configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py index 6c86a395e1f..7fea97473ae 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from ._configuration_group_values_operations import ConfigurationGroupValuesOperations +from configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations diff --git a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py index 6c86a395e1f..7fea97473ae 100644 --- a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from ._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from ._configuration_group_values_operations import ConfigurationGroupValuesOperations +from configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations From 7088b067ff771f1acb51beb71f3d29f9ccaa914f Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 16:03:43 +0100 Subject: [PATCH 04/13] style --- .../generate_nfd/nfd_generator_base.py | 4 +++- .../generate_nfd/vnf_bicep_nfd_generator.py | 17 ++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py b/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py index 21c2f0c5bac..81afb4db802 100644 --- a/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py +++ b/src/aosm/azext_aosm/generate_nfd/nfd_generator_base.py @@ -16,7 +16,9 @@ def __init__( self, ) -> None: """ - Superclass for NFD generators. The sub-classes do the actual work + Superclass for NFD generators. + + The sub-classes do the actual work """ pass diff --git a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py index d27c9642a23..88dd29c1b09 100644 --- a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py @@ -26,18 +26,17 @@ class VnfBicepNfdGenerator(NFDGenerator): """ - VNF NFD Generator. - + VNF NFD Generator. + This takes a source ARM template and a config file, and outputs: - A bicep file for the NFDV - - Parameters files that are used by the NFDV bicep file, these are the + - Parameters files that are used by the NFDV bicep file, these are the deployParameters and the mapping profiles of those deploy parameters - A bicep file for the Artifact manifests """ def __init__(self, config: VNFConfiguration): - super(NFDGenerator, self).__init__( - ) + super(NFDGenerator, self).__init__() self.config = config self.bicep_template_name = VNF_DEFINITION_BICEP_SOURCE_TEMPLATE self.manifest_template_name = VNF_MANIFEST_BICEP_SOURCE_TEMPLATE @@ -61,9 +60,7 @@ def generate_nfd(self) -> None: self.write() def write(self) -> None: - """ - Create a bicep template for an NFD from the ARM template for the VNF. - """ + """Create a bicep template for an NFD from the ARM template for the VNF.""" logger.info(f"Generate NFD bicep template for {self.arm_template_path}") print(f"Generate NFD bicep template for {self.arm_template_path}") @@ -200,9 +197,7 @@ def write_vhd_parameters(self, folder_path: str) -> None: logger.debug(f"{vhd_parameters_path} created") def copy_bicep(self) -> None: - """ - Copy the bicep templates into the build output folder. - """ + """Copy the bicep templates into the build output folder.""" code_dir = os.path.dirname(__file__) bicep_path = os.path.join(code_dir, "templates", self.bicep_template_name) From 3e224a2947c5af8847316b734e967fec9923d163 Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 16:19:01 +0100 Subject: [PATCH 05/13] lint and reverse some renames --- src/aosm/azext_aosm/__init__.py | 2 +- .../{client_factory.py => _client_factory.py} | 0 .../azext_aosm/{validators.py => _validators.py} | 0 src/aosm/azext_aosm/commands.py | 2 +- src/aosm/azext_aosm/configuration.py | 12 +++++++++--- src/aosm/azext_aosm/custom.py | 10 +++++----- 6 files changed, 16 insertions(+), 10 deletions(-) rename src/aosm/azext_aosm/{client_factory.py => _client_factory.py} (100%) rename src/aosm/azext_aosm/{validators.py => _validators.py} (100%) diff --git a/src/aosm/azext_aosm/__init__.py b/src/aosm/azext_aosm/__init__.py index a9098c4d1fb..c81f2e277cc 100644 --- a/src/aosm/azext_aosm/__init__.py +++ b/src/aosm/azext_aosm/__init__.py @@ -13,7 +13,7 @@ def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType aosm_custom = CliCommandType(operations_tmpl="azext_aosm.custom#{}") - super(AosmCommandsLoader, self).__init__( + super().__init__( cli_ctx=cli_ctx, custom_command_type=aosm_custom ) diff --git a/src/aosm/azext_aosm/client_factory.py b/src/aosm/azext_aosm/_client_factory.py similarity index 100% rename from src/aosm/azext_aosm/client_factory.py rename to src/aosm/azext_aosm/_client_factory.py diff --git a/src/aosm/azext_aosm/validators.py b/src/aosm/azext_aosm/_validators.py similarity index 100% rename from src/aosm/azext_aosm/validators.py rename to src/aosm/azext_aosm/_validators.py diff --git a/src/aosm/azext_aosm/commands.py b/src/aosm/azext_aosm/commands.py index 0f65c359929..c906ca6947e 100644 --- a/src/aosm/azext_aosm/commands.py +++ b/src/aosm/azext_aosm/commands.py @@ -7,7 +7,7 @@ from azure.cli.core import AzCommandsLoader # from azure.cli.core.commands import CliCommandType -from azext_aosm.client_factory import cf_aosm +from azext_aosm._client_factory import cf_aosm def load_command_table(self: AzCommandsLoader, _): diff --git a/src/aosm/azext_aosm/configuration.py b/src/aosm/azext_aosm/configuration.py index b9a93efa6a2..c0b6e1bdc7a 100644 --- a/src/aosm/azext_aosm/configuration.py +++ b/src/aosm/azext_aosm/configuration.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Dict, Optional, Any -from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError from pathlib import Path +from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError from azext_aosm.util.constants import VNF_DEFINITION_OUTPUT_BICEP_PREFIX, VNF, CNF, NSD DESCRIPTION_MAP: Dict[str, str] = { @@ -13,8 +13,14 @@ "location": "Azure location of the resources", "blob_artifact_store_name": "Name of the storage account Artifact Store resource", "artifact_name": "Name of the artifact", - "file_path": "Optional. File path of the artifact you wish to upload from your local disk. Delete if not required.", - "blob_sas_url": "Optional. SAS URL of the blob artifact you wish to copy to your Artifact Store. Delete if not required.", + "file_path": ( + "Optional. File path of the artifact you wish to upload from your " + "local disk. Delete if not required." + ), + "blob_sas_url": ( + "Optional. SAS URL of the blob artifact you wish to copy to your " + "Artifact Store. Delete if not required." + ), "artifact_version": ( "Version of the artifact. For VHDs this must be in format A-B-C. " "For ARM templates this must be in format A.B.C" diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index feccdfdd1a5..171ca767b2f 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -5,18 +5,18 @@ import json from dataclasses import asdict -from knack.log import get_logger from typing import Optional +from knack.log import get_logger from azext_aosm.generate_nfd.cnf_nfd_generator import CnfNfdGenerator from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator from azext_aosm.generate_nfd.vnf_bicep_nfd_generator import VnfBicepNfdGenerator from azext_aosm.deploy.deploy_with_arm import DeployerViaArm -from azext_aosm.util.constants import VNF, CNF, NSD +from azext_aosm.util.constants import VNF, CNF #, NSD from azext_aosm.util.management_clients import ApiClients -from .vendored_sdks import HybridNetworkManagementClient -from .client_factory import cf_resources -from configuration import get_configuration, validate_configuration, Configuration +from azext_aosm.vendored_sdks import HybridNetworkManagementClient +from azext_aosm._client_factory import cf_resources +from azext_aosm.configuration import get_configuration, validate_configuration, Configuration logger = get_logger(__name__) From 155c53316e8ec1d336e1ece9b80cee5891d8464b Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 16:29:58 +0100 Subject: [PATCH 06/13] dev instructions --- src/aosm/setup.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/aosm/setup.md diff --git a/src/aosm/setup.md b/src/aosm/setup.md new file mode 100644 index 00000000000..72158ac3d44 --- /dev/null +++ b/src/aosm/setup.md @@ -0,0 +1,46 @@ +### Prerequisites + +1. `python 3.8+` + + +### Dev environment setup + +Follow [https://github.com/Azure/azure-cli-dev-tools](https://github.com/Azure/azure-cli-dev-tools) + +Clone both azure-cli and azure-cli-extensions +```bash +# Go into your git clone of az-cli-extensions +cd az-cli-extensions + +# Create a virtual environment to run in +python3.8 -m venv ~/.virtualenvs/az-cli-env +source ~/.virtualenvs/az-cli-env/bin/activate + +# Ensure you have pip +python -m pip install -U pip + +# Install azdev +pip install azdev + +# Install all the python dependencies you need +azdev setup --cli /home/developer/code/azure-cli --repo . + +# Add the extension to your local CLI +azdev extension add aosm +``` +### VSCode environment setup. + +Make sure your VSCode is running in the same python virtual environment + +### Linting and Tests +```bash +azdev style aosm +azdev linter --include-whl-extensions aosm +(Not written any tests yet) +azdev test aosm +``` +You can use python-static-checks in your dev environment if you want, to help you: +```bash +pip3 install -U --index-url https://pkgs.dev.azure.com/msazuredev/AzureForOperators/_packaging/python/pypi/simple/ python-static-checks==4.0.0 +python-static-checks fmt +``` From edd5d1022ea2020bc5b11a14fc0889a033b141ca Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 17:08:00 +0100 Subject: [PATCH 07/13] oops. bad find and replace work. --- .../vendored_sdks/_hybrid_network_management_client.py | 2 +- .../vendored_sdks/aio/_hybrid_network_management_client.py | 2 +- src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py | 4 ++-- src/aosm/azext_aosm/vendored_sdks/operations/__init__.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py index b3e1f4fbb59..aa35ac07132 100644 --- a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py @@ -14,7 +14,7 @@ from azure.mgmt.core import ARMPipelineClient from . import models -from configuration import HybridNetworkManagementClientConfiguration +from _configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py index d1f51fc70f8..05b0ab4e4b5 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py @@ -15,7 +15,7 @@ from azure.mgmt.core import AsyncARMPipelineClient from .. import models -from configuration import HybridNetworkManagementClientConfiguration +from._configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py index 7fea97473ae..fd005f9ca27 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from configuration_group_values_operations import ConfigurationGroupValuesOperations +from._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from._configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations diff --git a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py index 7fea97473ae..fd005f9ca27 100644 --- a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from configuration_group_values_operations import ConfigurationGroupValuesOperations +from._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from._configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations From d2e19c28bd1feb4b208163204e6f4fd1a70dc678 Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 17:17:53 +0100 Subject: [PATCH 08/13] undo friday afternoon bad changes --- .../{configuration.py => _configuration.py} | 0 src/aosm/azext_aosm/custom.py | 2 +- src/aosm/azext_aosm/delete/delete.py | 2 +- src/aosm/azext_aosm/deploy/artifact.py | 2 +- .../azext_aosm/deploy/artifact_manifest.py | 2 +- src/aosm/azext_aosm/deploy/deploy_with_arm.py | 2 +- src/aosm/azext_aosm/deploy/pre_deploy.py | 2 +- .../generate_nfd/vnf_bicep_nfd_generator.py | 2 +- src/aosm/azext_aosm/test.py | 38 ------------------- .../_hybrid_network_management_client.py | 2 +- .../aio/_hybrid_network_management_client.py | 2 +- .../vendored_sdks/aio/operations/__init__.py | 4 +- .../vendored_sdks/operations/__init__.py | 4 +- 13 files changed, 13 insertions(+), 51 deletions(-) rename src/aosm/azext_aosm/{configuration.py => _configuration.py} (100%) delete mode 100644 src/aosm/azext_aosm/test.py diff --git a/src/aosm/azext_aosm/configuration.py b/src/aosm/azext_aosm/_configuration.py similarity index 100% rename from src/aosm/azext_aosm/configuration.py rename to src/aosm/azext_aosm/_configuration.py diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index 171ca767b2f..9e8905d99e3 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -16,7 +16,7 @@ from azext_aosm.util.management_clients import ApiClients from azext_aosm.vendored_sdks import HybridNetworkManagementClient from azext_aosm._client_factory import cf_resources -from azext_aosm.configuration import get_configuration, validate_configuration, Configuration +from azext_aosm._configuration import get_configuration, validate_configuration, Configuration logger = get_logger(__name__) diff --git a/src/aosm/azext_aosm/delete/delete.py b/src/aosm/azext_aosm/delete/delete.py index 1d83ab489d6..40d7987f086 100644 --- a/src/aosm/azext_aosm/delete/delete.py +++ b/src/aosm/azext_aosm/delete/delete.py @@ -12,7 +12,7 @@ ) from azext_aosm.util.management_clients import ApiClients -from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm.util.utils import input_ack diff --git a/src/aosm/azext_aosm/deploy/artifact.py b/src/aosm/azext_aosm/deploy/artifact.py index b457a672c8e..b8b0287b117 100644 --- a/src/aosm/azext_aosm/deploy/artifact.py +++ b/src/aosm/azext_aosm/deploy/artifact.py @@ -7,7 +7,7 @@ from typing import Union from azure.storage.blob import BlobClient -from azext_aosm.configuration import ArtifactConfig, DESCRIPTION_MAP +from azext_aosm._configuration import ArtifactConfig, DESCRIPTION_MAP from oras.client import OrasClient logger = get_logger(__name__) diff --git a/src/aosm/azext_aosm/deploy/artifact_manifest.py b/src/aosm/azext_aosm/deploy/artifact_manifest.py index 27ac2f003da..0d460a717c0 100644 --- a/src/aosm/azext_aosm/deploy/artifact_manifest.py +++ b/src/aosm/azext_aosm/deploy/artifact_manifest.py @@ -10,7 +10,7 @@ from azext_aosm.deploy.artifact import Artifact from azure.storage.blob import BlobClient from oras.client import OrasClient -from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm.vendored_sdks.models import ArtifactAccessCredential, ArtifactManifest from azext_aosm.util.management_clients import ApiClients diff --git a/src/aosm/azext_aosm/deploy/deploy_with_arm.py b/src/aosm/azext_aosm/deploy/deploy_with_arm.py index 61dd1ff5346..c422f6fc2dc 100644 --- a/src/aosm/azext_aosm/deploy/deploy_with_arm.py +++ b/src/aosm/azext_aosm/deploy/deploy_with_arm.py @@ -16,7 +16,7 @@ from pathlib import Path from azext_aosm.deploy.pre_deploy import PreDeployerViaSDK -from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm.util.constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, diff --git a/src/aosm/azext_aosm/deploy/pre_deploy.py b/src/aosm/azext_aosm/deploy/pre_deploy.py index 174d5ddadca..320139efadf 100644 --- a/src/aosm/azext_aosm/deploy/pre_deploy.py +++ b/src/aosm/azext_aosm/deploy/pre_deploy.py @@ -18,7 +18,7 @@ NetworkServiceDesignGroup, Publisher, ) -from azext_aosm.configuration import Configuration, VNFConfiguration +from azext_aosm._configuration import Configuration, VNFConfiguration from azext_aosm.util.constants import PROV_STATE_SUCCEEDED logger = get_logger(__name__) diff --git a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py index 88dd29c1b09..2b0768c6291 100644 --- a/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py +++ b/src/aosm/azext_aosm/generate_nfd/vnf_bicep_nfd_generator.py @@ -14,7 +14,7 @@ from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator -from azext_aosm.configuration import VNFConfiguration +from azext_aosm._configuration import VNFConfiguration from azext_aosm.util.constants import ( VNF_DEFINITION_BICEP_SOURCE_TEMPLATE, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, diff --git a/src/aosm/azext_aosm/test.py b/src/aosm/azext_aosm/test.py deleted file mode 100644 index 4c914d0dc3c..00000000000 --- a/src/aosm/azext_aosm/test.py +++ /dev/null @@ -1,38 +0,0 @@ -from azext_aosm.vendored_sdks import HybridNetworkManagementClient -from azext_aosm.vendored_sdks.models import ( - NetworkFunctionDefinitionVersion, - NetworkFunctionDefinitionGroup, - ArtifactManifest, - ManifestArtifactFormat, - VersionState, - NetworkFunctionType, - NFVIType, - ArtifactType, - VirtualNetworkFunctionDefinitionVersion, # this is actually properties, badly named - AzureCoreNetworkFunctionTemplate, - AzureCoreNetworkFunctionVhdApplication, - AzureCoreNetworkFunctionArmTemplateApplication, -) - -vnf_props = VirtualNetworkFunctionDefinitionVersion( - version_state=VersionState.PREVIEW, - deploy_parameters="TODO", - network_function_template=AzureCoreNetworkFunctionTemplate( - network_function_applications=[ - AzureCoreNetworkFunctionVhdApplication(), - AzureCoreNetworkFunctionArmTemplateApplication(), - ] - ), -) - -# test_dict = dict(**vnf_props) -print(vnf_props.__dict__) - -nfdv = NetworkFunctionDefinitionVersion( - location="uksouth", - # network_function_type="VirtualNetworkFunction", - # Think kwargs map magically to properties in bicep, somehow - **vnf_props.__dict__ -) - -print(nfdv) diff --git a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py index aa35ac07132..fa704c623bc 100644 --- a/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/_hybrid_network_management_client.py @@ -14,7 +14,7 @@ from azure.mgmt.core import ARMPipelineClient from . import models -from _configuration import HybridNetworkManagementClientConfiguration +from ._configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py index 05b0ab4e4b5..891ddcb7041 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/_hybrid_network_management_client.py @@ -15,7 +15,7 @@ from azure.mgmt.core import AsyncARMPipelineClient from .. import models -from._configuration import HybridNetworkManagementClientConfiguration +from ._configuration import HybridNetworkManagementClientConfiguration from .operations import ArtifactManifestsOperations, ArtifactStoresOperations, ComponentsOperations, ConfigurationGroupSchemasOperations, ConfigurationGroupValuesOperations, HybridNetworkManagementClientOperationsMixin, NetworkFunctionDefinitionGroupsOperations, NetworkFunctionDefinitionVersionsOperations, NetworkFunctionReadyK8SOperations, NetworkFunctionsOperations, NetworkServiceDesignGroupsOperations, NetworkServiceDesignVersionsOperations, Operations, PreviewSubscriptionsOperations, ProxyArtifactOperations, ProxyNetworkFunctionDefinitionGroupsOperations, ProxyNetworkFunctionDefinitionVersionsOperations, ProxyPublisherOperations, PublishersOperations, SiteNetworkServicesOperations, SitesOperations if TYPE_CHECKING: diff --git a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py index fd005f9ca27..6c86a395e1f 100644 --- a/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/aio/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from._configuration_group_values_operations import ConfigurationGroupValuesOperations +from ._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from ._configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations diff --git a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py index fd005f9ca27..6c86a395e1f 100644 --- a/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py +++ b/src/aosm/azext_aosm/vendored_sdks/operations/__init__.py @@ -6,8 +6,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations -from._configuration_group_values_operations import ConfigurationGroupValuesOperations +from ._configuration_group_schemas_operations import ConfigurationGroupSchemasOperations +from ._configuration_group_values_operations import ConfigurationGroupValuesOperations from ._network_functions_operations import NetworkFunctionsOperations from ._components_operations import ComponentsOperations from ._network_function_definition_groups_operations import NetworkFunctionDefinitionGroupsOperations From 1aaa00a6931e548353c449ce4e70dc4a0196dcaa Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 17:36:16 +0100 Subject: [PATCH 09/13] manifest optional --- src/aosm/azext_aosm/__init__.py | 4 +- src/aosm/azext_aosm/_params.py | 18 ++++++- src/aosm/azext_aosm/custom.py | 53 ++++++++++++------- src/aosm/azext_aosm/deploy/deploy_with_arm.py | 23 ++++++-- src/aosm/setup.md | 3 ++ 5 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/aosm/azext_aosm/__init__.py b/src/aosm/azext_aosm/__init__.py index c81f2e277cc..c15badcb435 100644 --- a/src/aosm/azext_aosm/__init__.py +++ b/src/aosm/azext_aosm/__init__.py @@ -13,9 +13,7 @@ def __init__(self, cli_ctx=None): from azure.cli.core.commands import CliCommandType aosm_custom = CliCommandType(operations_tmpl="azext_aosm.custom#{}") - super().__init__( - cli_ctx=cli_ctx, custom_command_type=aosm_custom - ) + super().__init__(cli_ctx=cli_ctx, custom_command_type=aosm_custom) def load_command_table(self, args): from azext_aosm.commands import load_command_table diff --git a/src/aosm/azext_aosm/_params.py b/src/aosm/azext_aosm/_params.py index 8fd8fd47cfd..9c13619fabf 100644 --- a/src/aosm/azext_aosm/_params.py +++ b/src/aosm/azext_aosm/_params.py @@ -44,8 +44,8 @@ def load_arguments(self: AzCommandsLoader, _): help="Also delete artifact stores, NFD Group and Publisher. Use with care.", ) c.argument( - "bicep_file", - options_list=["--bicep-file", "-b"], + "definition_file", + options_list=["--definition-file", "-b"], type=file_type, completer=FilesCompleter(allowednames="*.json"), help="Optional path to a bicep file to publish. Use to override publish of the built definition with an alternative file.", @@ -57,6 +57,20 @@ def load_arguments(self: AzCommandsLoader, _): completer=FilesCompleter(allowednames="*.json"), help="Optional path to a parameters file for the bicep definition file. Use to override publish of the built definition and config with alternative parameters.", ) + c.argument( + "manifest_file", + options_list=["--manifest-file", "-m"], + type=file_type, + completer=FilesCompleter(allowednames="*.json"), + help="Optional path to a bicep file to publish manifests. Use to override publish of the built definition with an alternative file.", + ) + c.argument( + "manifest_parameters_json_file", + options_list=["--manifest-parameters-file", "-mp"], + type=file_type, + completer=FilesCompleter(allowednames="*.json"), + help="Optional path to a parameters file for the manifest definition file. Use to override publish of the built definition and config with alternative parameters.", + ) with self.argument_context("aosm generate-config") as c: c.argument( diff --git a/src/aosm/azext_aosm/custom.py b/src/aosm/azext_aosm/custom.py index 9e8905d99e3..b615e67916e 100644 --- a/src/aosm/azext_aosm/custom.py +++ b/src/aosm/azext_aosm/custom.py @@ -12,11 +12,15 @@ from azext_aosm.generate_nfd.nfd_generator_base import NFDGenerator from azext_aosm.generate_nfd.vnf_bicep_nfd_generator import VnfBicepNfdGenerator from azext_aosm.deploy.deploy_with_arm import DeployerViaArm -from azext_aosm.util.constants import VNF, CNF #, NSD +from azext_aosm.util.constants import VNF, CNF # , NSD from azext_aosm.util.management_clients import ApiClients from azext_aosm.vendored_sdks import HybridNetworkManagementClient from azext_aosm._client_factory import cf_resources -from azext_aosm._configuration import get_configuration, validate_configuration, Configuration +from azext_aosm._configuration import ( + get_configuration, + validate_configuration, + Configuration, +) logger = get_logger(__name__) @@ -32,14 +36,12 @@ def build_definition( """ Build and optionally publish a definition. - :param cmd: _description_ + :param cmd: :type cmd: _type_ - :param client: _description_ + :param client: :type client: HybridNetworkManagementClient - :param definition_type: _description_ - :type definition_type: _type_ - :param config_file: _description_ - :type config_file: _type_ + :param config_file: path to the file + :param definition_type: VNF, CNF or NSD :param publish: _description_, defaults to False :type publish: bool, optional """ @@ -47,11 +49,11 @@ def build_definition( aosm_client=client, resource_client=cf_resources(cmd.cli_ctx) ) + # Read the config from the given file config = _get_config_from_file(config_file, definition_type) # Generate the NFD/NSD and the artifact manifest. _generate_nfd(definition_type=definition_type, config=config) - # Write the ARM/bicep template if that's what we are doing # Publish the definition if publish is true if publish: @@ -63,6 +65,13 @@ def build_definition( def generate_definition_config(definition_type: str, output_file: str = "input.json"): + """ + Generate an example config file for building a definition. + + :param definition_type: CNF, VNF or NSD + :param output_file: path to output config file, defaults to "input.json" + :type output_file: str, optional + """ config = get_configuration(definition_type) config_as_dict = json.dumps(asdict(config), indent=4) @@ -89,12 +98,7 @@ def _get_config_from_file(config_file: str, definition_type: str) -> Configurati def _generate_nfd(definition_type, config): - """ - _summary_ - - :param definition_type: _description_ - :type definition_type: _type_ - """ + """Generate a Network Function Definition for the given type and config.""" nfd_generator: NFDGenerator if definition_type == VNF: nfd_generator = VnfBicepNfdGenerator(config) @@ -115,24 +119,30 @@ def publish_definition( client: HybridNetworkManagementClient, definition_type, config_file, - bicep_file: Optional[str] = None, + definition_file: Optional[str] = None, parameters_json_file: Optional[str] = None, + manifest_file: Optional[str] = None, + manifest_parameters_json_file: Optional[str] = None, ): """ - _summary_ + 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 bicep_file: Optional path to a bicep template to deploy, in case the user + :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 + 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: Optional path to an override bicep parameters + file for manifest parameters """ print("Publishing definition.") api_clients = ApiClients( @@ -142,7 +152,10 @@ def publish_definition( if definition_type == VNF: deployer = DeployerViaArm(api_clients, config=config) deployer.deploy_vnfd_from_bicep( - bicep_path=bicep_file, parameters_json_file=parameters_json_file + bicep_path=definition_file, + parameters_json_file=parameters_json_file, + manifest_bicep_path=manifest_file, + manifest_parameters_json_file=manifest_parameters_json_file, ) diff --git a/src/aosm/azext_aosm/deploy/deploy_with_arm.py b/src/aosm/azext_aosm/deploy/deploy_with_arm.py index c422f6fc2dc..753cb4864bf 100644 --- a/src/aosm/azext_aosm/deploy/deploy_with_arm.py +++ b/src/aosm/azext_aosm/deploy/deploy_with_arm.py @@ -53,14 +53,20 @@ def deploy_vnfd_from_bicep( self, bicep_path: Optional[str] = None, parameters_json_file: Optional[str] = None, + manifest_bicep_path: Optional[str] = None, + manifest_parameters_json_file: Optional[str] = None, ) -> None: """ Deploy the bicep template defining the VNFD. Also ensure that all required predeploy resources are deployed. - :param bicep_template_path: The path to the bicep template of the + :param bicep_template_path: The path to the bicep template of the nfdv :type bicep_template_path: str + :parameters_json_file: path to an override file of set parameters for the nfdv + :param manifest_bicep_path: The path to the bicep template of the manifest + :manifest_parameters_json_file: path to an override file of set parameters for + the manifest """ assert isinstance(self.config, VNFConfiguration) @@ -93,10 +99,17 @@ def deploy_vnfd_from_bicep( if deploy_manifest_template: print(f"Deploy bicep template for Artifact manifests") logger.debug("Deploy manifest bicep") - manifest_bicep_path = os.path.join( - self.config.build_output_folder_name, VNF_MANIFEST_BICEP_SOURCE_TEMPLATE - ) - manifest_params = self.construct_manifest_parameters() + if not manifest_bicep_path: + manifest_bicep_path = os.path.join( + self.config.build_output_folder_name, + VNF_MANIFEST_BICEP_SOURCE_TEMPLATE, + ) + if not manifest_parameters_json_file: + manifest_params = self.construct_manifest_parameters() + else: + logger.info("Use provided manifest parameters") + with open(manifest_parameters_json_file, "r", encoding="utf-8") as f: + manifest_params = json.loads(f.read()) self.deploy_bicep_template(manifest_bicep_path, manifest_params) else: print( diff --git a/src/aosm/setup.md b/src/aosm/setup.md index 72158ac3d44..1930f5f1246 100644 --- a/src/aosm/setup.md +++ b/src/aosm/setup.md @@ -28,6 +28,9 @@ azdev setup --cli /home/developer/code/azure-cli --repo . # Add the extension to your local CLI azdev extension add aosm ``` +### Generating the AOSM Python SDK +TODO + ### VSCode environment setup. Make sure your VSCode is running in the same python virtual environment From 1c598cb6939d3838ff76d6664e5983e09d16b446 Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 17:58:25 +0100 Subject: [PATCH 10/13] Basic README --- src/aosm/README.md | 57 +++++++++++++++++++++++++++++++++++++++++++++ src/aosm/README.rst | 5 ---- 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/aosm/README.md delete mode 100644 src/aosm/README.rst diff --git a/src/aosm/README.md b/src/aosm/README.md new file mode 100644 index 00000000000..61c796677aa --- /dev/null +++ b/src/aosm/README.md @@ -0,0 +1,57 @@ +# Microsoft Azure CLI 'aosm' Extension +========================================== + +This package is for the 'aosm' extension to support Azure Operator Service Manager +functions. +i.e. `az aosm` + +Install via `az extension add --name aosm` + + +# Background +The `az aosm` extension provides support for publishing Network Function Definitions +to use with Azure Operator Service Manager or Network Function Manager. + +# Pre-requisites +## VNFs +For VNFs, you will need a single ARM template which would create the Azure resources +for your VNF, for example a Virtual Machine, disks and NICs. You'll also need a VHD +image that would be used for the VNF Virtual Machine. + +# Command examples + +Get help on command arguments + +`az aosm -h` +`az aosm definition -h` +`az aosm definition build -h` +etc... + +All these commands take a `--definition-type` argument of `vnf`, `cnf` or (coming) `nsd` + +Create an example config file for building a definition + +`az aosm definition generate-config --config-file input.json` + +This will output a file called `input.json` which must be filled in. +Once the config file has been filled in the following commands can be run. + +Build a definition locally + +`az aosm definition build --config-file input.json` + +Build and publish a definition + +`az aosm definition build --config-file input.json --publish` + +Publish a pre-built definition + +`az aosm definition publish --config-file input.json` + +Delete a published definition + +`az aosm definition delete --config-file input.json` + +Delete a published definition and the publisher, artifact stores and NFD group + +`az aosm definition delete --config-file input.json --clean` diff --git a/src/aosm/README.rst b/src/aosm/README.rst deleted file mode 100644 index dca4757fd38..00000000000 --- a/src/aosm/README.rst +++ /dev/null @@ -1,5 +0,0 @@ -Microsoft Azure CLI 'aosm' Extension -========================================== - -This package is for the 'aosm' extension. -i.e. 'az aosm' \ No newline at end of file From 985ceb276e251533d68757d9146c0ccb9fb3079a Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 17:59:21 +0100 Subject: [PATCH 11/13] delete publisher definition --- .../templates/publisher_definition.bicep | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/aosm/azext_aosm/generate_nfd/templates/publisher_definition.bicep diff --git a/src/aosm/azext_aosm/generate_nfd/templates/publisher_definition.bicep b/src/aosm/azext_aosm/generate_nfd/templates/publisher_definition.bicep deleted file mode 100644 index 62fd4aef354..00000000000 --- a/src/aosm/azext_aosm/generate_nfd/templates/publisher_definition.bicep +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Highly Confidential Material -// Bicep template to create a Publisher -param location string = resourceGroup().location -@description('Name you want to give the new Publisher object') -param publisherName string - -resource publisher 'Microsoft.HybridNetwork/publishers@2022-09-01-preview' = { - name: publisherName - scope: resourceGroup() - location: location - properties: { - scope: 'Private' - } -} From eb83c78c14242002d7f56692b9bf4881e5e06a32 Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 18:00:25 +0100 Subject: [PATCH 12/13] unwanted constant --- src/aosm/azext_aosm/util/constants.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/aosm/azext_aosm/util/constants.py b/src/aosm/azext_aosm/util/constants.py index 6933f42f511..93c149185a1 100644 --- a/src/aosm/azext_aosm/util/constants.py +++ b/src/aosm/azext_aosm/util/constants.py @@ -4,8 +4,6 @@ # -------------------------------------------------------------------------------------------- """Constants used across aosm cli extension.""" -AOSM_API_VERSION = "2022-09-01-preview" - # The types of definition that can be generated VNF = "vnf" CNF = "cnf" From fe87a115af9993e06925a71ab9b9aa7297eb2af9 Mon Sep 17 00:00:00 2001 From: Sunny Carter Date: Fri, 5 May 2023 18:17:27 +0100 Subject: [PATCH 13/13] d --- src/aosm/azext_aosm/delete/delete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aosm/azext_aosm/delete/delete.py b/src/aosm/azext_aosm/delete/delete.py index 40d7987f086..05a9904d7db 100644 --- a/src/aosm/azext_aosm/delete/delete.py +++ b/src/aosm/azext_aosm/delete/delete.py @@ -152,7 +152,7 @@ def delete_nfdg(self) -> None: network_function_definition_group_name=self.config.nfdg_name, ) poller.result() - print("Delete NFD Group") + print("Deleted NFD Group") except Exception: logger.error(f"Failed to delete NFDG.") raise