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

Sunny/choose deploy parameters #23

Merged
merged 14 commits into from
Jun 9, 2023
4 changes: 4 additions & 0 deletions src/aosm/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Release History
===============

unreleased
++++++++++
* `az aosm nfd build` options `--order-params` and `--interactive` to help users choose which NF parameters to expose as deployParameters. Feature added that allows CNF value mappings file to be generated if none is supplied.

0.2.0
++++++
Breaking change to commands - now use `nfd` instead of `definition`. Publish option removed from build.
Expand Down
18 changes: 16 additions & 2 deletions src/aosm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ image that would be used for the VNF Virtual Machine.

#### CNFs

For CNFs, you must provide helm packages with an associated schema. When filling in the input.json file, you must list helm packages in the order they are to be deployed. For example, if A must be deployed before B, your input.json should look something like this:
For CNFs, you must provide helm packages with an associated schema.
Optionally, you can provide a file path_to_mappings which is a copy of values.yaml with your chosen values replaced by deployment parameters, thus exposing them as parameters to the CNF. You can get this file auto-generated by leaving the value as a blank string, either having every value as
a deployment parameter, or using --interactive to interactively choose.
When filling in the input.json file, you must list helm packages in the order they are to be deployed. For example, if A must be deployed before B, your input.json should look something like this:

"helm_packages": [
{
Expand Down Expand Up @@ -115,6 +118,17 @@ Build an nfd definition locally

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

More options on building an nfd definition locally:

Choose which of the VNF ARM template parameters you want to expose as NFD deploymentParameters, with the option of interactively choosing each one.

`az aosm nfd build --config-file input.json --definition_type vnf --order_params`
`az aosm nfd build --config-file input.json --definition_type vnf --order_params --interactive`

Choose which of the CNF Helm values parameters you want to expose as NFD deploymentParameters.

`az aosm nfd build --config-file input.json --definition_type cnf [--interactive]`

Publish a pre-built definition

`az aosm nfd publish --config-file input.json`
Expand Down Expand Up @@ -157,4 +171,4 @@ Delete a published design

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

`az aosm nsd delete --config-file input.json --clean`
`az aosm nsd delete --config-file input.json --clean`
1 change: 1 addition & 0 deletions src/aosm/azext_aosm/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.cli.core.profiles import ResourceType

from .vendored_sdks import HybridNetworkManagementClient


Expand Down
61 changes: 38 additions & 23 deletions src/aosm/azext_aosm/_configuration.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
## Disabling as every if statement in validate in NSConfig class has this condition
# pylint: disable=simplifiable-condition

import os
from dataclasses import dataclass, field
from typing import Dict, Optional, Any, List
from pathlib import Path
import os
from azure.cli.core.azclierror import ValidationError, InvalidArgumentValueError
from typing import Any, Dict, List, Optional

from azure.cli.core.azclierror import InvalidArgumentValueError, ValidationError

from azext_aosm.util.constants import (
DEFINITION_OUTPUT_BICEP_PREFIX,
VNF,
CNF,
DEFINITION_OUTPUT_BICEP_PREFIX,
NF_DEFINITION_JSON_FILE,
NSD,
NSD_DEFINITION_OUTPUT_BICEP_PREFIX,
NF_DEFINITION_JSON_FILE,
VNF,
)


DESCRIPTION_MAP: Dict[str, str] = {
"publisher_resource_group_name":
"Resource group for the Publisher resource. Will be created if it does not exist."
,
"Resource group for the Publisher resource. "
"Will be created if it does not exist.",
"publisher_name":
"Name of the Publisher resource you want your definition published to. Will be created if it does not exist."
,
"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 should be the same as the publisher used for your NFDVs"
Expand All @@ -33,7 +34,8 @@
"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.",
"blob_artifact_store_name":
"Name of the storage account Artifact Store resource. Will be created if it does not exist.",
"Name of the storage account Artifact Store resource. Will be created if it "
"does not exist.",
"artifact_name": "Name of the artifact",
"file_path":
"Optional. File path of the artifact you wish to upload from your local disk. "
Expand All @@ -60,7 +62,12 @@
"path_to_chart":
"File path of Helm Chart on local disk. Accepts .tgz, .tar or .tar.gz",
"path_to_mappings":
"File path of value mappings on local disk. Accepts .yaml or .yml",
"File path of value mappings on local disk where chosen values are replaced "
"with deploymentParameter placeholders. Accepts .yaml or .yml. If left as a "
"blank string, a value mappings file will be generated with every value "
"mapped to a deployment parameter. Use a blank string and --interactive on "
"the build command to interactively choose which values to map."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm interested in when you think the --interactive mode is going to be better than editing the file once it is generated? Maybe when you have a massive values.yaml and you only want to expose a couple of parameters??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it right that this is done during the "build" command? Or should it be a seperate command? (It's genuinely unclear to me).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a quick discussion

,
"helm_depends_on":
"Names of the Helm packages this package depends on. "
"Leave as an empty array if no dependencies",
Expand Down Expand Up @@ -121,24 +128,33 @@ class NSConfiguration:
nsdv_description: str = DESCRIPTION_MAP["nsdv_description"]

def validate(self):
""" Validate that all of the configuration parameters are set """
"""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 "":
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 "":
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 ""
== 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 ""
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 (
Expand Down Expand Up @@ -173,8 +189,7 @@ def network_function_name(self) -> str:
@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('.', '-')}"
return f"{self.network_function_name.lower().replace('_', '-')}-acr-manifest-{self.nsd_version.replace('.', '-')}"

@property
def nfvi_site_name(self) -> str:
Expand All @@ -195,10 +210,10 @@ def arm_template(self) -> ArtifactConfig:
self.build_output_folder_name, NF_DEFINITION_JSON_FILE
)
return artifact

@property
def arm_template_artifact_name(self) -> str:
"""Return the artifact name for the ARM template"""
"""Return the artifact name for the ARM template."""
return f"{self.network_function_definition_group_name}_nfd_artifact"


Expand Down
1 change: 0 additions & 1 deletion src/aosm/azext_aosm/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from knack.help_files import helps # pylint: disable=unused-import


helps[
"aosm"
] = """
Expand Down
18 changes: 17 additions & 1 deletion src/aosm/azext_aosm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from argcomplete.completers import FilesCompleter
from azure.cli.core import AzCommandsLoader

from .util.constants import VNF, CNF, NSD
from .util.constants import CNF, VNF


def load_arguments(self: AzCommandsLoader, _):
Expand Down Expand Up @@ -52,6 +52,22 @@ def load_arguments(self: AzCommandsLoader, _):
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(
"order_params",
arg_type=get_three_state_flag(),
help="VNF definition_type only - ignored for CNF."
" Order deploymentParameters schema and configMappings to have the "
"parameters without default values at the top and those with default "
"values at the bottom. Can make it easier to remove those with defaults "
"which you do not want to expose as NFD parameters.",
)
c.argument(
"interactive",
options_list=["--interactive", "-i"],
arg_type=get_three_state_flag(),
help="Prompt user to choose every parameter to expose as an NFD parameter."
" Those without defaults are automatically included.",
)
c.argument(
"parameters_json_file",
options_list=["--parameters-file", "-p"],
Expand Down
54 changes: 35 additions & 19 deletions src/aosm/azext_aosm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,40 @@
import shutil
from dataclasses import asdict
from typing import Optional
from knack.log import get_logger

from azure.cli.core.azclierror import (
CLIInternalError,
InvalidArgumentValueError,
UnclassifiedUserFault,
)
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_nsd.nsd_generator import NSDGenerator
from azext_aosm.generate_nfd.vnf_nfd_generator import VnfNfdGenerator
from azext_aosm.delete.delete import ResourceDeleter
from azext_aosm.deploy.deploy_with_arm import DeployerViaArm
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,
CNFConfiguration,
NFConfiguration,
NSConfiguration,
VNFConfiguration,
get_configuration,
)

from azext_aosm.delete.delete import ResourceDeleter
from azext_aosm.deploy.deploy_with_arm import DeployerViaArm
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_nfd_generator import VnfNfdGenerator
from azext_aosm.generate_nsd.nsd_generator import NSDGenerator
from azext_aosm.util.constants import CNF, NSD, VNF
from azext_aosm.util.management_clients import ApiClients
from azext_aosm.vendored_sdks import HybridNetworkManagementClient

logger = get_logger(__name__)


def build_definition(
definition_type: str,
config_file: str,
order_params: bool = False,
interactive: bool = False,
):
"""
Build a definition.
Expand All @@ -54,7 +58,12 @@ def build_definition(
)

# Generate the NFD and the artifact manifest.
_generate_nfd(definition_type=definition_type, config=config)
_generate_nfd(
definition_type=definition_type,
config=config,
order_params=order_params,
interactive=interactive,
)


def generate_definition_config(definition_type: str, output_file: str = "input.json"):
Expand Down Expand Up @@ -90,13 +99,17 @@ def _get_config_from_file(
return config


def _generate_nfd(definition_type, config):
def _generate_nfd(
definition_type: str, config: NFConfiguration, order_params: bool, interactive: bool
):
"""Generate a Network Function Definition for the given type and config."""
nfd_generator: NFDGenerator
if definition_type == VNF:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could simplify this and get rid of definition_type by doing the if tests based on the config class type. Up to you whether that is worthwhile.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, can't be bothered :)

nfd_generator = VnfNfdGenerator(config)
assert isinstance(config, VNFConfiguration)
nfd_generator = VnfNfdGenerator(config, order_params, interactive)
elif definition_type == CNF:
nfd_generator = CnfNfdGenerator(config)
assert isinstance(config, CNFConfiguration)
nfd_generator = CnfNfdGenerator(config, interactive)
else:
raise CLIInternalError(
"Generate NFD called for unrecognised definition_type. Only VNF and CNF have been implemented."
Expand Down Expand Up @@ -215,6 +228,7 @@ def delete_published_definition(
def generate_design_config(output_file: str = "input.json"):
"""
Generate an example config file for building a NSD.

:param output_file: path to output config file, defaults to "input.json"
:type output_file: str, optional
"""
Expand All @@ -224,6 +238,7 @@ def generate_design_config(output_file: str = "input.json"):
def _generate_config(configuration_type: str, output_file: str = "input.json"):
"""
Generic generate config function for NFDs and NSDs.

:param configuration_type: CNF, VNF or NSD
:param output_file: path to output config file, defaults to "input.json"
:type output_file: str, optional
Expand All @@ -240,7 +255,7 @@ def _generate_config(configuration_type: str, output_file: str = "input.json"):

with open(output_file, "w", encoding="utf-8") as f:
f.write(config_as_dict)
if configuration_type == CNF or configuration_type == VNF:
if configuration_type in (CNF,VNF):
prtName = "definition"
else:
prtName = "design"
Expand All @@ -251,6 +266,7 @@ def _generate_config(configuration_type: str, output_file: str = "input.json"):
def build_design(cmd, client: HybridNetworkManagementClient, config_file: str):
"""
Build a Network Service Design.

:param cmd:
:type cmd: _type_
:param client:
Expand Down Expand Up @@ -282,6 +298,7 @@ def delete_published_design(
):
"""
Delete a published NSD.

:param config_file: Path to the config file
:param clean: if True, will delete the NSDG, artifact stores and publisher too.
Defaults to False. Only works if no resources have those as a parent.
Expand All @@ -308,6 +325,7 @@ def publish_design(
):
"""
Publish a generated design.

:param cmd:
:param client:
:type client: HybridNetworkManagementClient
Expand Down Expand Up @@ -347,8 +365,6 @@ def _generate_nsd(config: NSDGenerator, api_clients):
if config:
nsd_generator = NSDGenerator(config)
else:
from azure.cli.core.azclierror import CLIInternalError

raise CLIInternalError("Generate NSD called without a config file")
deploy_parameters = _get_nfdv_deployment_parameters(config, api_clients)

Expand Down
3 changes: 1 addition & 2 deletions src/aosm/azext_aosm/delete/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
"""Contains class for deploying generated definitions using the Python SDK."""
from knack.log import get_logger

from azext_aosm._configuration import NFConfiguration, NSConfiguration, VNFConfiguration
from azext_aosm.util.management_clients import ApiClients
from azext_aosm._configuration import NFConfiguration, VNFConfiguration, NSConfiguration
from azext_aosm.util.utils import input_ack


logger = get_logger(__name__)


Expand Down
Loading