Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pk5/add nsd cli #15

Merged
merged 19 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions src/aosm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,14 @@ For CNFs, you must provide helm packages with an associated schema. When filling
]
},

#### NSDs
For NSDs, you will need to have a Resource Group with a deployed Publisher, Artifact Store, Network Function Definition and Network Function Definition Version. You can use the `az aosm nfd` commands to create all of these resources.


### Command examples

#### NFDs

Get help on command arguments

`az aosm -h`
Expand All @@ -107,10 +113,6 @@ Build an nfd definition locally

`az aosm nfd build --config-file input.json`

Build and publish a definition

`az aosm nfd build --config-file input.json --publish`

Publish a pre-built definition

`az aosm nfd publish --config-file input.json`
Expand All @@ -123,6 +125,34 @@ Delete a published definition and the publisher, artifact stores and NFD group

`az aosm nfd delete --config-file input.json --clean`

Coming soon:
#### NSDs

Get help on command arguments

`az aosm -h`
`az aosm nsd -h`
`az aosm nsd build -h`
etc...

Create an example config file for building a definition

`az aosm nsd generate-config`

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 an nsd locally

`az aosm nsd build --config-file input.json`

Publish a pre-built design

`az aosm nsd publish --config-file input.json`

Delete a published design

`az aosm nsd delete --config-file input.json`

Delete a published design and the publisher, artifact stores and NSD group

`az aosm nsd build` and further nsd commands.
`az aosm nsd delete --config-file input.json --clean`
159 changes: 147 additions & 12 deletions src/aosm/azext_aosm/_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
from typing import Dict, Optional, Any, List
from pathlib import Path
from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError
from azext_aosm.util.constants import DEFINITION_OUTPUT_BICEP_PREFIX, VNF, CNF, NSD
from azext_aosm.util.constants import (
DEFINITION_OUTPUT_BICEP_PREFIX,
VNF,
CNF,
NSD,
SCHEMA,
NSD_DEFINITION_OUTPUT_BICEP_PREFIX,
NF_DEFINITION_JSON_FILE,
)
import os

DESCRIPTION_MAP: Dict[str, str] = {
"publisher_resource_group_name": (
Expand All @@ -13,10 +22,14 @@
"Name of the Publisher resource you want your definition "
"published to. Will be created if it does not exist."
),
"publisher_name_nsd": (
"Name of the Publisher resource you want your design published to. This published should be the same as the publisher used for your NFDVs"
),
"publisher_resource_group_name_nsd": ("Resource group for the Publisher resource."),
"nf_name": "Name of NF definition",
"version": "Version of the NF definition",
"acr_artifact_store_name": "Name of the ACR Artifact Store resource. Will be created if it does not exist.",
"location": "Azure location to use when creating resources",
"location": "Azure location to use when creating resources.",
"blob_artifact_store_name": "Name of the storage account Artifact Store resource. Will be created if it does not exist.",
"artifact_name": "Name of the artifact",
"file_path": (
patrykkulik-microsoft marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -31,14 +44,21 @@
"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"
),
"nsdv_description": "Description of the NSDV",
"nsdg_name": "Network Service Design Group Name. This is the collection of Network Service Design Versions. Will be "
"created if it does not exist.",
"nsd_version": "Version of the NSD to be created. This should be in the format A.B.C",
"network_function_definition_group_name": "Exising Network Function Definition Group Name. This can be created using the 'az aosm nfd' commands.",
"network_function_definition_version_name": "Exising Network Function Definition Version Name. This can be created using the 'az aosm nfd' commands.",
"network_function_definition_offering_location": "Offering location of the Network Function Definition",
"helm_package_name": "Name of the Helm package",
"path_to_chart": (
"File path of Helm Chart on local disk. Accepts .tgz, .tar or .tar.gz"
),
"helm_depends_on": (
"Names of the Helm packages this package depends on. "
"Leave as an empty array if no dependencies"
)
),
}


Expand Down Expand Up @@ -74,6 +94,123 @@ def acr_manifest_name(self) -> str:
return f"{self.nf_name}-acr-manifest-{self.version.replace('.', '-')}"


@dataclass
class NSConfiguration:
location: str = DESCRIPTION_MAP["location"]
publisher_name: str = DESCRIPTION_MAP["publisher_name_nsd"]
publisher_resource_group_name: str = DESCRIPTION_MAP[
"publisher_resource_group_name_nsd"
]
acr_artifact_store_name: str = DESCRIPTION_MAP["acr_artifact_store_name"]
network_function_definition_group_name: str = DESCRIPTION_MAP[
"network_function_definition_group_name"
]
network_function_definition_version_name: str = DESCRIPTION_MAP[
"network_function_definition_version_name"
]
network_function_definition_offering_location: str = DESCRIPTION_MAP[
"network_function_definition_offering_location"
]
nsdg_name: str = DESCRIPTION_MAP["nsdg_name"]
nsd_version: str = DESCRIPTION_MAP["nsd_version"]
nsdv_description: str = DESCRIPTION_MAP["nsdv_description"]

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)

def validate(self):
## validate that all of the configuration parameters are set

if self.location == DESCRIPTION_MAP["location"] or "":
raise ValueError("Location must be set")
if self.publisher_name == DESCRIPTION_MAP["publisher_name_nsd"] or "":
raise ValueError("Publisher name must be set")
if (
self.publisher_resource_group_name
== DESCRIPTION_MAP["publisher_resource_group_name_nsd"]
or ""
):
raise ValueError("Publisher resource group name must be set")
if (
self.acr_artifact_store_name == DESCRIPTION_MAP["acr_artifact_store_name"]
or ""
):
raise ValueError("ACR Artifact Store name must be set")
if (
self.network_function_definition_group_name
== DESCRIPTION_MAP["network_function_definition_group_name"]
or ""
):
raise ValueError("Network Function Definition Group name must be set")
if (
self.network_function_definition_version_name
== DESCRIPTION_MAP["network_function_definition_version_name"]
or ""
):
raise ValueError("Network Function Definition Version name must be set")
if (
self.network_function_definition_offering_location
== DESCRIPTION_MAP["network_function_definition_offering_location"]
or ""
):
raise ValueError(
"Network Function Definition Offering Location must be set"
)
if self.nsdg_name == DESCRIPTION_MAP["nsdg_name"] or "":
raise ValueError("NSDG name must be set")
if self.nsd_version == DESCRIPTION_MAP["nsd_version"] or "":
raise ValueError("NSD Version must be set")

@property
def build_output_folder_name(self) -> str:
"""Return the local folder for generating the bicep template to."""
current_working_directory = os.getcwd()
patrykkulik-microsoft marked this conversation as resolved.
Show resolved Hide resolved
return f"{current_working_directory}/{NSD_DEFINITION_OUTPUT_BICEP_PREFIX}"

@property
def resource_element_name(self) -> str:
"""Return the name of the resource element."""
artifact_name = self.arm_template.artifact_name
return f"{artifact_name}-resource-element"

@property
def network_function_name(self) -> str:
"""Return the name of the NFVI used for the NSDV."""
return f"{self.nsdg_name}_NF"

@property
def acr_manifest_name(self) -> str:
"""Return the ACR manifest name from the NFD name."""
return f"{self.network_function_name.lower().replace('_', '-')}-acr-manifest-{self.nsd_version.replace('.', '-')}"

@property
def nfvi_site_name(self) -> str:
"""Return the name of the NFVI used for the NSDV."""
return f"{self.nsdg_name}_NFVI"

@property
def cg_schema_name(self) -> str:
"""Return the name of the Configuration Schema used for the NSDV."""
return f"{self.nsdg_name.replace('-', '_')}_ConfigGroupSchema"

@property
def arm_template(self) -> ArtifactConfig:
"""Return the parameters of the ARM template to be uploaded as part of the NSDV."""
artifact = ArtifactConfig()
artifact.artifact_name = f"{self.nsdg_name.lower()}_nf_artifact"
artifact.version = self.nsd_version
artifact.file_path = os.path.join(
self.build_output_folder_name, NF_DEFINITION_JSON_FILE
)
return artifact


@dataclass
class VNFConfiguration(NFConfiguration):
blob_artifact_store_name: str = DESCRIPTION_MAP["blob_artifact_store_name"]
Expand Down Expand Up @@ -140,9 +277,7 @@ def sa_manifest_name(self) -> str:
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"{DEFINITION_OUTPUT_BICEP_PREFIX}{Path(str(arm_template_path)).stem}"
)
return f"{DEFINITION_OUTPUT_BICEP_PREFIX}{Path(str(arm_template_path)).stem}"


@dataclass
Expand Down Expand Up @@ -175,17 +310,17 @@ def build_output_folder_name(self) -> str:


def get_configuration(
definition_type: str, config_as_dict: Optional[Dict[Any, Any]] = None
) -> NFConfiguration:
configuration_type: str, config_as_dict: Optional[Dict[Any, Any]] = None
) -> NFConfiguration or NSConfiguration:
if config_as_dict is None:
config_as_dict = {}

if definition_type == VNF:
if configuration_type == VNF:
config = VNFConfiguration(**config_as_dict)
elif definition_type == CNF:
elif configuration_type == CNF:
config = CNFConfiguration(**config_as_dict)
elif definition_type == NSD:
config = NFConfiguration(**config_as_dict)
elif configuration_type == NSD:
config = NSConfiguration(**config_as_dict)
else:
raise InvalidArgumentValueError(
"Definition type not recognized, options are: vnf, cnf or nsd"
Expand Down
13 changes: 8 additions & 5 deletions src/aosm/azext_aosm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def load_arguments(self: AzCommandsLoader, _):

# Set the argument context so these options are only available when this specific command
# is called.

with self.argument_context("aosm nfd") as c:
c.argument(
"definition_type", arg_type=definition_type, help="Type of AOSM definition."
Expand All @@ -44,6 +45,13 @@ def load_arguments(self: AzCommandsLoader, _):
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(
"design_file",
options_list=["--design-file", "-b"],
type=file_type,
completer=FilesCompleter(allowednames="*.bicep"),
help="Optional path to a bicep file to publish. Use to override publish of the built design with an alternative file.",
)
c.argument(
"parameters_json_file",
options_list=["--parameters-file", "-p"],
Expand Down Expand Up @@ -74,8 +82,3 @@ def load_arguments(self: AzCommandsLoader, _):
completer=FilesCompleter(allowednames="*.json"),
help="The path to the configuration file.",
)
c.argument(
"clean",
arg_type=get_three_state_flag(),
help="Also delete artifact stores, NFD Group and Publisher. Use with care.",
)
Loading