Skip to content

Commit

Permalink
Check for Azure features on deploy and delete (#71)
Browse files Browse the repository at this point in the history
* WIP: Check for features on deploy and delete

* linting

* Anand has confirmed names of flags

* Update test recording as now has calls to Features API

* Update src/aosm/azext_aosm/custom.py

Co-authored-by: jamiedparsons <111778988+jamiedparsons@users.noreply.github.com>

* docstring markups

---------

Co-authored-by: jamiedparsons <111778988+jamiedparsons@users.noreply.github.com>
  • Loading branch information
sunnycarter and jamiedparsons committed Aug 31, 2023
1 parent a28cbc5 commit 28e3262
Show file tree
Hide file tree
Showing 5 changed files with 1,891 additions and 982 deletions.
7 changes: 7 additions & 0 deletions src/aosm/azext_aosm/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ def cf_resources(cli_ctx, subscription_id=None):
)


def cf_features(cli_ctx, subscription_id=None):
"""Return the client for checking feature enablement."""
return get_mgmt_service_client(
cli_ctx, ResourceType.MGMT_RESOURCE_FEATURES, subscription_id=subscription_id
)


def cf_acr_registries(cli_ctx, *_) -> ContainerRegistryManagementClient:
"""
Returns the client for managing container registries.
Expand Down
131 changes: 115 additions & 16 deletions src/aosm/azext_aosm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
InvalidArgumentValueError,
UnclassifiedUserFault,
)
from azure.cli.core.commands import AzCliCommand
from azure.core import exceptions as azure_exceptions
from knack.log import get_logger

from azext_aosm._client_factory import cf_acr_registries, cf_resources
from azext_aosm._client_factory import cf_acr_registries, cf_features, cf_resources
from azext_aosm._configuration import (
CNFConfiguration,
Configuration,
Expand All @@ -32,7 +34,15 @@
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, DeployableResourceTypes, NSD, SkipSteps, VNF
from azext_aosm.util.constants import (
AOSM_FEATURE_NAMESPACE,
AOSM_REQUIRED_FEATURES,
CNF,
NSD,
VNF,
DeployableResourceTypes,
SkipSteps,
)
from azext_aosm.util.management_clients import ApiClients
from azext_aosm.vendored_sdks import HybridNetworkManagementClient

Expand All @@ -49,10 +59,11 @@ def build_definition(
"""
Build a definition.
:param cmd:
:type cmd: _type_
:param definition_type: VNF or CNF
:param config_file: path to the file
:param definition_type: VNF, CNF
:param interactive - whether to prompt for input when creating deploy parameters
mapping files
:param force: force the build even if the design has already been built
"""

Expand Down Expand Up @@ -135,8 +146,54 @@ def _generate_nfd(
nfd_generator.generate_nfd()


def _check_features_enabled(cmd: AzCliCommand):
"""
Check that the required Azure features are enabled on the subscription.
:param cmd: The AzCLICommand object for the original command that was run, we use
this to retrieve the CLI context in order to get the features client for access
to the features API.
"""
features_client = cf_features(cmd.cli_ctx)
# Check that the required features are enabled on the subscription
for feature in AOSM_REQUIRED_FEATURES:
try:
feature_result = features_client.features.get(
resource_provider_namespace=AOSM_FEATURE_NAMESPACE,
feature_name=feature,
)
if (
not feature_result
or not feature_result.properties.state == "Registered"
):
# We don't want to log the name of the feature to the user as it is
# a hidden feature. We do want to log it to the debug log though.
logger.debug(
"Feature %s is not registered on the subscription.", feature
)
raise CLIInternalError(
"Your Azure subscription has not been fully onboarded to AOSM. "
"Please see the AOSM onboarding documentation for more information."
)
except azure_exceptions.ResourceNotFoundError as rerr:
# If the feature is not found, it is not registered, but also something has
# gone wrong with the CLI code and onboarding instructions.
logger.debug(
"Feature not found error - Azure doesn't recognise the feature %s."
"This indicates a coding error or error with the AOSM onboarding "
"instructions.",
feature,
)
logger.debug(rerr)
raise CLIInternalError(
"CLI encountered an error checking that your "
"subscription has been onboarded to AOSM. Please raise an issue against"
" the CLI."
) from rerr


def publish_definition(
cmd,
cmd: AzCliCommand,
client: HybridNetworkManagementClient,
definition_type,
config_file,
Expand All @@ -149,8 +206,13 @@ def publish_definition(
"""
Publish a generated definition.
:param cmd:
:param client:
:param cmd: The AzCLICommand object for the command that was run, we use this to
find the CLI context (from which, for example, subscription id and
credentials can be found, and other clients can be generated.)
:param client: The AOSM client. This is created in _client_factory.py and passed
in by commands.py - we could alternatively just use cf_aosm as
we use cf_resources, but other extensions seem to pass a client
around like this.
:type client: HybridNetworkManagementClient
:param definition_type: VNF or CNF
:param config_file: Path to the config file for the NFDV
Expand All @@ -166,6 +228,9 @@ def publish_definition(
file for manifest parameters
:param skip: options to skip, either publish bicep or upload artifacts
"""
# Check that the required features are enabled on the subscription
_check_features_enabled(cmd)

print("Publishing definition.")
api_clients = ApiClients(
aosm_client=client,
Expand Down Expand Up @@ -198,7 +263,7 @@ def publish_definition(


def delete_published_definition(
cmd,
cmd: AzCliCommand,
client: HybridNetworkManagementClient,
definition_type,
config_file,
Expand All @@ -208,13 +273,23 @@ def delete_published_definition(
"""
Delete a published definition.
:param cmd: The AzCLICommand object for the command that was run, we use this to
find the CLI context (from which, for example, subscription id and
credentials can be found, and other clients can be generated.)
:param client: The AOSM client. This is created in _client_factory.py and passed
in by commands.py - we could alternatively just use cf_aosm as
we use cf_resources, but other extensions seem to pass a client
around like this.
: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.
:param force: if True, will not prompt for confirmation before deleting the resources.
"""
# Check that the required features are enabled on the subscription
_check_features_enabled(cmd)

config = _get_config_from_file(
config_file=config_file, configuration_type=definition_type
)
Expand Down Expand Up @@ -282,14 +357,21 @@ def _generate_config(configuration_type: str, output_file: str = "input.json"):


def build_design(
cmd, client: HybridNetworkManagementClient, config_file: str, force: bool = False
cmd: AzCliCommand,
client: HybridNetworkManagementClient,
config_file: str,
force: bool = False,
):
"""
Build a Network Service Design.
:param cmd:
:type cmd: _type_
:param client:
:param cmd: The AzCLICommand object for the command that was run, we use this to
find the CLI context (from which, for example, subscription id and
credentials can be found, and other clients can be generated.)
:param client: The AOSM client. This is created in _client_factory.py and passed
in by commands.py - we could alternatively just use cf_aosm as
we use cf_resources, but other extensions seem to pass a client
around like this.
:type client: HybridNetworkManagementClient
:param config_file: path to the file
:param force: force the build, even if the design has already been built
Expand All @@ -314,7 +396,7 @@ def build_design(


def delete_published_design(
cmd,
cmd: AzCliCommand,
client: HybridNetworkManagementClient,
config_file,
clean=False,
Expand All @@ -323,13 +405,23 @@ def delete_published_design(
"""
Delete a published NSD.
:param cmd: The AzCLICommand object for the command that was run, we use this to
find the CLI context (from which, for example, subscription id and
credentials can be found, and other clients can be generated.)
:param client: The AOSM client. This is created in _client_factory.py and passed
in by commands.py - we could alternatively just use cf_aosm as
we use cf_resources, but other extensions seem to pass a client
around like this.
: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.
Use with care.
:param clean: if True, will delete the NSDG on top of the other resources.
:param force: if True, will not prompt for confirmation before deleting the resources.
"""
# Check that the required features are enabled on the subscription
_check_features_enabled(cmd)

config = _get_config_from_file(config_file=config_file, configuration_type=NSD)

api_clients = ApiClients(
Expand All @@ -341,7 +433,7 @@ def delete_published_design(


def publish_design(
cmd,
cmd: AzCliCommand,
client: HybridNetworkManagementClient,
config_file,
design_file: Optional[str] = None,
Expand All @@ -353,8 +445,13 @@ def publish_design(
"""
Publish a generated design.
:param cmd:
:param client:
:param cmd: The AzCLICommand object for the command that was run, we use this to
find the CLI context (from which, for example, subscription id and
credentials can be found, and other clients can be generated.)
:param client: The AOSM client. This is created in _client_factory.py and passed
in by commands.py - we could alternatively just use cf_aosm as
we use cf_resources, but other extensions seem to pass a client
around like this.
:type client: HybridNetworkManagementClient
:param config_file: Path to the config file for the NSDV
:param design_file: Optional path to an override bicep template to deploy the NSDV.
Expand All @@ -368,6 +465,8 @@ def publish_design(
file for manifest parameters
:param skip: options to skip, either publish bicep or upload artifacts
"""
# Check that the required features are enabled on the subscription
_check_features_enabled(cmd)

print("Publishing design.")
api_clients = ApiClients(
Expand Down
Loading

0 comments on commit 28e3262

Please sign in to comment.