Skip to content

Commit

Permalink
Pk5/add nsd cli (Azure#15)
Browse files Browse the repository at this point in the history
* First working version of the CLI NSD create

* Fully working version of the NSD CLI

* minor change to nsd_generate

* Sunny's refactor

* First round of cleanup

* Secound Round of cleanup

* fix the 2023 api NSDV

* description updates

* deleted comment

* Fix SNS creation

* Fix SNS creation try 2

* markups

* delete unnecessary file

* Testing markups

* Fix the SNS attempt 3

* minor fixes

* Fix config validation
  • Loading branch information
patrykkulik-microsoft authored Jun 2, 2023
1 parent 371a1ea commit dda5957
Show file tree
Hide file tree
Showing 16 changed files with 1,108 additions and 150 deletions.
42 changes: 36 additions & 6 deletions src/aosm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,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 @@ -109,10 +115,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 @@ -125,6 +127,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": (
Expand All @@ -31,6 +44,13 @@
"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"
Expand All @@ -41,7 +61,7 @@
"helm_depends_on": (
"Names of the Helm packages this package depends on. "
"Leave as an empty array if no dependencies"
)
),
}


Expand Down Expand Up @@ -77,6 +97,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()
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 @@ -143,9 +280,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 @@ -179,17 +314,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

0 comments on commit dda5957

Please sign in to comment.