Skip to content

Commit

Permalink
Sundry fixes for CNF quickstart (Azure#38)
Browse files Browse the repository at this point in the history
* Sundry fixes for CNF quickstart

* merge add-aosm-ext in (Azure#37)

* markups
  • Loading branch information
sunnycarter authored Jul 4, 2023
1 parent f06efc3 commit 0f86392
Show file tree
Hide file tree
Showing 13 changed files with 408 additions and 242 deletions.
7 changes: 7 additions & 0 deletions src/aosm/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ unreleased
* NFDV version exposed as a CGV on an SNS.
* `az aosm nfd publish` option added for `--definition-type cnf` to publish the CNF bicep templates, upload helm charts from disk to the ACR and copy the images from a source ACR to the target ACR.
* Managed Identity added to VNF NF templates - requires subscription to be registered for the feature flag.
* Various fixes to NFD build of deployParameters schema and interactive mode create of deployParameters mappings file.
* Fix CNF NFD publish so that it doesn't render the ACR unuseable for future Artifact publishing.
* Allow CNF NFD image copy from a source ACR using a namespace.
* Fix - Add new CGSchema parameters not from the NFD to the `required` section of the schema.
* Add the ability to skip bicep publish or artifact upload during publish commands.
* Fix Manifest name for NSDs so it isn't the same as that for NFDs
* Add validation of source_registry_id format for CNF configuration

0.2.0
++++++
Expand Down
32 changes: 29 additions & 3 deletions src/aosm/azext_aosm/_configuration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional
Expand All @@ -12,6 +13,7 @@
NSD,
NSD_OUTPUT_BICEP_PREFIX,
VNF,
SOURCE_ACR_REGEX
)

DESCRIPTION_MAP: Dict[str, str] = {
Expand Down Expand Up @@ -95,6 +97,13 @@
"source_registry_id": (
"Resource ID of the source acr registry from which to pull the image"
),
"source_registry_namespace": (
"Optional. Namespace of the repository of the source acr registry from which "
"to pull. For example if your repository is samples/prod/nginx then set this to"
" samples/prod . Leave blank if the image is in the root namespace."
"See https://learn.microsoft.com/en-us/azure/container-registry/"
"container-registry-best-practices#repository-namespaces for further details."
),
}


Expand Down Expand Up @@ -220,8 +229,10 @@ def network_function_name(self) -> str:
@property
def acr_manifest_name(self) -> str:
"""Return the ACR manifest name from the NFD name."""
sanitised_nf_name = self.network_function_name.lower().replace("_", "-")
return f"{sanitised_nf_name}-acr-manifest-{self.nsd_version.replace('.', '-')}"
sanitised_nf_name = self.network_function_name.lower().replace('_', '-')
return (
f"{sanitised_nf_name}-nsd-acr-manifest-{self.nsd_version.replace('.', '-')}"
)

@property
def nfvi_site_name(self) -> str:
Expand All @@ -246,7 +257,7 @@ def arm_template(self) -> ArtifactConfig:
@property
def arm_template_artifact_name(self) -> str:
"""Return the artifact name for the ARM template."""
return f"{self.network_function_definition_group_name}_nfd_artifact"
return f"{self.network_function_definition_group_name}-nfd-artifact"


@dataclass
Expand Down Expand Up @@ -337,6 +348,7 @@ class HelmPackageConfig:
@dataclass
class CNFConfiguration(NFConfiguration):
source_registry_id: str = DESCRIPTION_MAP["source_registry_id"]
source_registry_namespace: str = DESCRIPTION_MAP["source_registry_namespace"]
helm_packages: List[Any] = field(default_factory=lambda: [HelmPackageConfig()])

def __post_init__(self):
Expand All @@ -354,6 +366,20 @@ def build_output_folder_name(self) -> str:
"""Return the local folder for generating the bicep template to."""
return f"{NF_DEFINITION_OUTPUT_BICEP_PREFIX}{self.nf_name}"

def validate(self):
"""Validate the CNF config
:raises ValidationError: If source registry ID doesn't match the regex
"""
if self.source_registry_id == DESCRIPTION_MAP["source_registry_id"]:
# Config has not been filled in. Don't validate.
return

source_registry_match = re.search(SOURCE_ACR_REGEX, self.source_registry_id)
if not source_registry_match or len(source_registry_match.groups()) < 2:
raise ValidationError(
"CNF config has an invalid source registry ID. Please run `az aosm "
"nfd generate-config` to see the valid formats.")

def get_configuration(
configuration_type: str, config_as_dict: Optional[Dict[Any, Any]] = None
Expand Down
9 changes: 8 additions & 1 deletion src/aosm/azext_aosm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from argcomplete.completers import FilesCompleter
from azure.cli.core import AzCommandsLoader

from .util.constants import CNF, VNF
from .util.constants import CNF, VNF, BICEP_PUBLISH, ARTIFACT_UPLOAD


def load_arguments(self: AzCommandsLoader, _):
Expand All @@ -17,6 +17,7 @@ def load_arguments(self: AzCommandsLoader, _):
)

definition_type = get_enum_type([VNF, CNF])
skip_steps = get_enum_type([BICEP_PUBLISH, ARTIFACT_UPLOAD])

# Set the argument context so these options are only available when this specific command
# is called.
Expand Down Expand Up @@ -109,6 +110,9 @@ def load_arguments(self: AzCommandsLoader, _):
" alternative parameters."
),
)
c.argument(
"skip", arg_type=skip_steps, help="Optional skip steps"
)

with self.argument_context("aosm nsd") as c:
c.argument(
Expand All @@ -118,3 +122,6 @@ def load_arguments(self: AzCommandsLoader, _):
completer=FilesCompleter(allowednames="*.json"),
help="The path to the configuration file.",
)
c.argument(
"skip", arg_type=skip_steps, help="Optional skip steps"
)
7 changes: 7 additions & 0 deletions src/aosm/azext_aosm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def publish_definition(
parameters_json_file: Optional[str] = None,
manifest_file: Optional[str] = None,
manifest_parameters_json_file: Optional[str] = None,
skip: Optional[str] = None,
):
"""
Publish a generated definition.
Expand All @@ -156,6 +157,7 @@ def publish_definition(
manifests
:param manifest_parameters_json_file: Optional path to an override bicep parameters
file for manifest parameters
:param skip: options to skip, either publish bicep or upload artifacts
"""
print("Publishing definition.")
api_clients = ApiClients(
Expand All @@ -175,6 +177,7 @@ def publish_definition(
parameters_json_file=parameters_json_file,
manifest_bicep_path=manifest_file,
manifest_parameters_json_file=manifest_parameters_json_file,
skip=skip
)
elif definition_type == CNF:
deployer = DeployerViaArm(api_clients, config=config)
Expand All @@ -184,6 +187,7 @@ def publish_definition(
parameters_json_file=parameters_json_file,
manifest_bicep_path=manifest_file,
manifest_parameters_json_file=manifest_parameters_json_file,
skip=skip
)
else:
raise ValueError(
Expand Down Expand Up @@ -328,6 +332,7 @@ def publish_design(
parameters_json_file: Optional[str] = None,
manifest_file: Optional[str] = None,
manifest_parameters_json_file: Optional[str] = None,
skip: Optional[str] = None,
):
"""
Publish a generated design.
Expand All @@ -345,6 +350,7 @@ def publish_design(
manifests
:param manifest_parameters_json_file: Optional path to an override bicep parameters
file for manifest parameters
:param skip: options to skip, either publish bicep or upload artifacts
"""

print("Publishing design.")
Expand All @@ -363,6 +369,7 @@ def publish_design(
parameters_json_file=parameters_json_file,
manifest_bicep_path=manifest_file,
manifest_parameters_json_file=manifest_parameters_json_file,
skip=skip
)


Expand Down
37 changes: 24 additions & 13 deletions src/aosm/azext_aosm/deploy/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"""A module to handle interacting with artifacts."""
import subprocess
from dataclasses import dataclass
from typing import Union
from typing import Union, List

from azure.cli.core.commands import LongRunningOperation
from azure.mgmt.containerregistry.models import ImportImageParameters, ImportSource
from azure.storage.blob import BlobClient, BlobType
from knack.log import get_logger
from knack.util import CLIError
from oras.client import OrasClient
from azure.cli.core.commands import LongRunningOperation
from azure.mgmt.containerregistry import ContainerRegistryManagementClient

from azext_aosm._configuration import ArtifactConfig, HelmPackageConfig

Expand Down Expand Up @@ -82,11 +84,18 @@ def _upload_helm_to_acr(self, artifact_config: HelmPackageConfig) -> None:
login_command = ["az", "acr", "login", "--name", registry_name]
subprocess.run(login_command, check=True)

logger.debug("Uploading %s to %s", chart_path, target_registry)

# helm push "$chart_path" "$target_registry"
push_command = ["helm", "push", chart_path, target_registry]
subprocess.run(push_command, check=True)
try:
logger.debug("Uploading %s to %s", chart_path, target_registry)

# helm push "$chart_path" "$target_registry"
push_command = ["helm", "push", chart_path, target_registry]
subprocess.run(push_command, check=True)
finally:
# If we don't logout from the registry, future Artifact uploads to this ACR
# will fail with an UNAUTHORIZED error. There is no az acr logout command,
# but it is a wrapper around docker, so a call to docker logout will work.
logout_command = ["docker", "logout", registry]
subprocess.run(logout_command, check=True)

def _upload_to_storage_account(self, artifact_config: ArtifactConfig) -> None:
"""
Expand Down Expand Up @@ -131,12 +140,13 @@ def _upload_to_storage_account(self, artifact_config: ArtifactConfig) -> None:
@staticmethod
def copy_image(
cli_ctx,
container_registry_client,
source_registry_id,
source_image,
target_registry_resource_group_name,
target_registry_name,
mode="NoForce",
container_registry_client: ContainerRegistryManagementClient,
source_registry_id: str,
source_image: str,
target_registry_resource_group_name: str,
target_registry_name: str,
target_tags: List[str],
mode: str = "NoForce",
):
"""
Copy image from one ACR to another.
Expand All @@ -147,9 +157,10 @@ def copy_image(
:param source_image: source image
:param target_registry_resource_group_name: target registry resource group name
:param target_registry_name: target registry name
:param target_tags: the list of tags to be applied to the imported image
should be of form: namepace/name:tag or name:tag
:param mode: mode for import
"""
target_tags = [source_image]

source = ImportSource(resource_id=source_registry_id, source_image=source_image)

Expand Down
Loading

0 comments on commit 0f86392

Please sign in to comment.