Skip to content
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
34 changes: 34 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_enterprise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=wrong-import-order

from knack.log import get_logger
from .custom import (_create_service)


logger = get_logger(__name__)


def spring_cloud_create(cmd, client, resource_group, name, location=None,
vnet=None, service_runtime_subnet=None, app_subnet=None, reserved_cidr_range=None,
service_runtime_network_resource_group=None, app_network_resource_group=None,
app_insights_key=None, app_insights=None, sampling_rate=None,
disable_app_insights=None, enable_java_agent=None,
sku=None, tags=None, no_wait=False):
"""
This method creates Azure Spring Cloud enterprise tier instance, it also creates sub-component under the instance if
user enable these component.
"""
poller = _create_service(cmd, client, resource_group, name,
location=location,
service_runtime_subnet=service_runtime_subnet,
app_subnet=app_subnet,
reserved_cidr_range=reserved_cidr_range,
service_runtime_network_resource_group=service_runtime_network_resource_group,
app_network_resource_group=app_network_resource_group,
sku=sku,
tags=tags)
return poller
7 changes: 6 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
text: az spring-cloud create -n MyService -g MyResourceGroup --vnet MyVNet --app-subnet MyAppSubnet --service-runtime-subnet MyServiceRuntimeSubnet
- name: Create a new Azure Spring Cloud with VNet-injected via giving subnets resource ID
text: az spring-cloud create -n MyService -g MyResourceGroup --app-subnet /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyVnetRg/providers/Microsoft.Network/VirtualNetworks/test-vnet/subnets/app --service-runtime-subnet /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyVnetRg/providers/Microsoft.Network/VirtualNetworks/test-vnet/subnets/svc --reserved-cidr-range 10.0.0.0/16,10.1.0.0/16,10.2.0.1/16
- name: Create a Azure Spring Cloud Enterprise instance if the Azure Subscription never hosts Azure Spring Cloud Enterprise instance
text: |
az provider register -n Microsoft.SaaS
az term accept --publisher vmware-inc --product azure-spring-cloud-vmware-tanzu-2 --plan tanzu-asc-ent-mtr
az spring-cloud create -n MyService -g MyResourceGroup --sku Enterprise
"""

helps['spring-cloud update'] = """
Expand Down Expand Up @@ -352,7 +357,7 @@

helps['spring-cloud config-server'] = """
type: group
short-summary: Commands to manage Config Server in Azure Spring Cloud.
short-summary: (Support Standard Tier and Basic Tier) Commands to manage Config Server in Azure Spring Cloud.
"""

helps['spring-cloud config-server show'] = """
Expand Down
4 changes: 3 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
validator=validate_env, help="Space-separated environment variables in 'key[=value]' format.", nargs='*')
service_name_type = CLIArgumentType(options_list=['--service', '-s'], help='Name of Azure Spring Cloud, you can configure the default service using az configure --defaults spring-cloud=<name>.', configured_default='spring-cloud')
app_name_type = CLIArgumentType(help='App name, you can configure the default app using az configure --defaults spring-cloud-app=<name>.', validator=validate_app_name, configured_default='spring-cloud-app')
sku_type = CLIArgumentType(arg_type=get_enum_type(['Basic', 'Standard', 'Enterprise']), validator=validate_sku, help='Name of SKU. Enterprise is still in Preview.')


# pylint: disable=too-many-statements
Expand All @@ -40,6 +41,7 @@ def load_arguments(self, _):
# https://dev.azure.com/msazure/AzureDMSS/_workitems/edit/11002857/
with self.argument_context('spring-cloud create') as c:
c.argument('location', arg_type=get_location_type(self.cli_ctx), validator=validate_location)
c.argument('sku', arg_type=sku_type, default='Standard')
c.argument('reserved_cidr_range', help='Comma-separated list of IP address ranges in CIDR format. The IP ranges are reserved to host underlying Azure Spring Cloud infrastructure, which should be 3 at least /16 unused IP ranges, must not overlap with any Subnet IP ranges.', validator=validate_vnet_required_parameters)
c.argument('vnet', help='The name or ID of an existing Virtual Network into which to deploy the Spring Cloud instance.', validator=validate_vnet_required_parameters)
c.argument('app_subnet', help='The name or ID of an existing subnet in "vnet" into which to deploy the Spring Cloud app. Required when deploying into a Virtual Network. Smaller subnet sizes are supported, please refer: https://aka.ms/azure-spring-cloud-smaller-subnet-vnet-docs', validator=validate_vnet_required_parameters)
Expand Down Expand Up @@ -72,6 +74,7 @@ def load_arguments(self, _):
validator=validate_tracing_parameters_asc_create)

with self.argument_context('spring-cloud update') as c:
c.argument('sku', arg_type=sku_type)
c.argument('app_insights_key',
help="Connection string (recommended) or Instrumentation key of the existing Application Insights.",
validator=validate_tracing_parameters_asc_update,
Expand All @@ -98,7 +101,6 @@ def load_arguments(self, _):

for scope in ['spring-cloud create', 'spring-cloud update']:
with self.argument_context(scope) as c:
c.argument('sku', type=str, validator=validate_sku, help='Name of SKU, the value is "Basic" or "Standard"')
c.argument('tags', arg_type=tags_type)

with self.argument_context('spring-cloud test-endpoint renew-key') as c:
Expand Down
18 changes: 18 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_util_enterprise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=wrong-import-order

from .vendored_sdks.appplatform.v2022_01_01_preview import AppPlatformManagementClient
from azure.cli.core.commands.client_factory import get_mgmt_service_client


def is_enterprise_tier(cmd, resource_group, name):
resource = get_client(cmd).services.get(resource_group, name)
return resource.sku.name == 'E0'


def get_client(cmd):
return get_mgmt_service_client(cmd.cli_ctx, AppPlatformManagementClient)
18 changes: 17 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
from enum import Enum
import os
from time import sleep
import codecs
import tarfile
import tempfile
Expand Down Expand Up @@ -222,6 +223,8 @@ def _get_sku_name(tier): # pylint: disable=too-many-return-statements
return 'B0'
if tier == 'STANDARD':
return 'S0'
if tier == 'ENTERPRISE':
return 'E0'
raise CLIError("Invalid sku(pricing tier), please refer to command help for valid values")


Expand All @@ -231,6 +234,8 @@ def _get_persistent_disk_size(tier): # pylint: disable=too-many-return-statemen
return 1
if tier == 'STANDARD':
return 50
if tier == 'ENTERPRISE':
return 50
return 50


Expand All @@ -243,11 +248,22 @@ def get_portal_uri(cli_ctx):
return 'https://portal.azure.com'


def wait_till_end(cmd, *pollers):
if not pollers:
return
progress_bar = cmd.cli_ctx.get_progress_controller()
progress_bar.add(message='Running')
progress_bar.begin()
while any(x and not x.done() for x in pollers):
progress_bar.add(message='Running')
sleep(5)


def handle_asc_exception(ex):
try:
raise CLIError(ex.inner_exception.error.message)
except AttributeError:
if hasattr(ex, 'response'):
if hasattr(ex, 'response') and ex.response.internal_response.text:
response_dict = json.loads(ex.response.internal_response.text)
raise CLIError(response_dict["error"]["message"])
else:
Expand Down
52 changes: 43 additions & 9 deletions src/spring-cloud/azext_spring_cloud/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.commands.validators import validate_tag
from azure.cli.core.azclierror import InvalidArgumentValueError
from ._utils import _get_file_type
from knack.validators import DefaultStr
from azure.mgmt.core.tools import is_valid_resource_id
from azure.mgmt.core.tools import parse_resource_id
from azure.mgmt.core.tools import resource_id
from knack.log import get_logger
from ._utils import ApiType
from ._utils import _get_rg_location
from ._utils import (ApiType, _get_rg_location, _get_file_type, _get_sku_name)
from .vendored_sdks.appplatform.v2020_07_01 import models

logger = get_logger(__name__)

Expand All @@ -40,11 +40,37 @@ def validate_location(namespace):
for piece in location_slice])


def validate_sku(namespace):
if namespace.sku is not None:
namespace.sku = namespace.sku.upper()
if namespace.sku not in ['BASIC', 'STANDARD']:
raise InvalidArgumentValueError("The pricing tier only accepts value [Basic, Standard]")
def validate_sku(cmd, namespace):
if not namespace.sku:
return
if namespace.sku.lower() == 'enterprise':
_validate_saas_provider(cmd, namespace)
_validate_terms(cmd, namespace)
namespace.sku = models.Sku(name=_get_sku_name(namespace.sku), tier=namespace.sku)


def _validate_saas_provider(cmd, namespace):
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.cli.core.profiles import ResourceType
client = get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES).providers
if client.get('Microsoft.SaaS').registration_state != 'Registered':
raise InvalidArgumentValueError('Microsoft.SaaS resource provider is not registered.\n'
'Run "az provider register -n Microsoft.SaaS" to register.')


def _validate_terms(cmd, namespace):
from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements
from azure.cli.core.commands.client_factory import get_mgmt_service_client
client = get_mgmt_service_client(cmd.cli_ctx, MarketplaceOrderingAgreements).marketplace_agreements
term = client.get(offer_type="virtualmachine",
publisher_id='vmware-inc',
offer_id='azure-spring-cloud-vmware-tanzu-2',
plan_id='tanzu-asc-ent-mtr')
if not term.accepted:
raise InvalidArgumentValueError('Terms for Azure Spring Cloud Enterprise is not accepted.\n'
'Run "az term accept --publisher vmware-inc '
'--product azure-spring-cloud-vmware-tanzu-2 '
'--plan tanzu-asc-ent-mtr" to accept the term.')


def validate_instance_count(namespace):
Expand Down Expand Up @@ -429,7 +455,7 @@ def validate_vnet_required_parameters(namespace):
not namespace.reserved_cidr_range and \
not namespace.vnet:
return
if namespace.sku and namespace.sku.lower() == 'basic':
if namespace.sku and _parse_sku_name(namespace.sku) == 'basic':
raise InvalidArgumentValueError('Virtual Network Injection is not supported for Basic tier.')
if not namespace.app_subnet \
or not namespace.service_runtime_subnet:
Expand All @@ -444,6 +470,14 @@ def validate_node_resource_group(namespace):
_validate_resource_group_name(namespace.app_network_resource_group, 'app-network-resource-group')


def _parse_sku_name(sku):
if not sku:
return 'standard'
if type(sku) is str or type(sku) is DefaultStr:
return sku.lower()
return sku.tier.lower()


def _validate_resource_group_name(name, message_name):
if not name:
return
Expand Down
11 changes: 10 additions & 1 deletion src/spring-cloud/azext_spring_cloud/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long
from azure.cli.core.commands import CliCommandType
from azext_spring_cloud._utils import handle_asc_exception

from ._client_factory import (cf_spring_cloud_20220101preview,
Expand All @@ -18,9 +19,17 @@

# pylint: disable=too-many-statements
def load_command_table(self, _):
with self.command_group('spring-cloud', client_factory=cf_spring_cloud_20220101preview,
spring_cloud_routing_util = CliCommandType(
operations_tmpl='azext_spring_cloud.tier_routing_spring_cloud#{}',
client_factory=cf_spring_cloud_20220101preview
)

with self.command_group('spring-cloud', custom_command_type=spring_cloud_routing_util,
exception_handler=handle_asc_exception) as g:
g.custom_command('create', 'spring_cloud_create', supports_no_wait=True)

with self.command_group('spring-cloud', client_factory=cf_spring_cloud_20220101preview,
exception_handler=handle_asc_exception) as g:
g.custom_command('update', 'spring_cloud_update', supports_no_wait=True)
g.custom_command('delete', 'spring_cloud_delete', supports_no_wait=True)
g.custom_command('start', 'spring_cloud_start', supports_no_wait=True)
Expand Down
45 changes: 30 additions & 15 deletions src/spring-cloud/azext_spring_cloud/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import yaml # pylint: disable=import-error
from time import sleep
from ._stream_utils import stream_logs
from azure.mgmt.core.tools import parse_resource_id, is_valid_resource_id
from ._utils import _get_upload_local_file, _get_persistent_disk_size, get_portal_uri, get_azure_files_info
from azure.mgmt.core.tools import (parse_resource_id, is_valid_resource_id)
from ._utils import (_get_upload_local_file, _get_persistent_disk_size,
get_portal_uri, get_azure_files_info,
wait_till_end)
from knack.util import CLIError
from .vendored_sdks.appplatform.v2020_07_01 import models
from .vendored_sdks.appplatform.v2020_11_01_preview import models as models_20201101preview
Expand All @@ -36,7 +38,6 @@
from azure.cli.core.commands import cached_put
from azure.core.exceptions import ResourceNotFoundError
from ._utils import _get_rg_location
from ._utils import _get_sku_name
from ._resource_quantity import validate_cpu, validate_memory
from six.moves.urllib import parse
from threading import Thread
Expand All @@ -63,8 +64,11 @@ def spring_cloud_create(cmd, client, resource_group, name, location=None,
service_runtime_network_resource_group=None, app_network_resource_group=None,
app_insights_key=None, app_insights=None, sampling_rate=None,
disable_app_insights=None, enable_java_agent=None,
sku='Standard', tags=None, no_wait=False):
sku=None, tags=None, no_wait=False):
"""
Note: This is the command for create Spring-Cloud Standard and Basic tier. Refer tier_routing_spring_cloud.py for
the command definition. And _enteprise.py for Spring-Cloud Enterprise tier creation.

If app_insights_key, app_insights and disable_app_insights are all None,
will still create an application insights and enable application insights.
:param enable_java_agent: (TODO) In deprecation process, ignore the value now. Will delete this.
Expand All @@ -74,6 +78,25 @@ def spring_cloud_create(cmd, client, resource_group, name, location=None,
# TODO (jiec) Deco this method when we deco parameter "--enable-java-agent"
_warn_enable_java_agent(enable_java_agent)

poller = _create_service(cmd, client, resource_group, name,
location=location,
service_runtime_subnet=service_runtime_subnet,
app_subnet=app_subnet,
reserved_cidr_range=reserved_cidr_range,
service_runtime_network_resource_group=service_runtime_network_resource_group,
app_network_resource_group=app_network_resource_group,
sku=sku,
tags=tags)
_update_application_insights_asc_create(cmd, resource_group, name, location,
app_insights_key, app_insights, sampling_rate,
disable_app_insights, no_wait)
return poller


def _create_service(cmd, client, resource_group, name, location=None,
service_runtime_subnet=None, app_subnet=None, reserved_cidr_range=None,
service_runtime_network_resource_group=None, app_network_resource_group=None,
sku=None, tags=None):
if location is None:
location = _get_rg_location(cmd.cli_ctx, resource_group)
properties = models.ClusterResourceProperties()
Expand All @@ -87,19 +110,12 @@ def spring_cloud_create(cmd, client, resource_group, name, location=None,
service_runtime_network_resource_group=service_runtime_network_resource_group
)

full_sku = models.Sku(name=_get_sku_name(sku), tier=sku)

resource = models.ServiceResource(location=location, sku=full_sku, properties=properties, tags=tags)
resource = models.ServiceResource(location=location, sku=sku, properties=properties, tags=tags)

poller = client.services.begin_create_or_update(
resource_group, name, resource)
logger.warning(" - Creating Service ..")
while poller.done() is False:
sleep(5)

_update_application_insights_asc_create(cmd, resource_group, name, location,
app_insights_key, app_insights, sampling_rate,
disable_app_insights, no_wait)
wait_till_end(cmd, poller)
return poller


Expand Down Expand Up @@ -138,8 +154,7 @@ def spring_cloud_update(cmd, client, resource_group, name, app_insights_key=None

# update service sku
if sku is not None:
full_sku = models.Sku(name=_get_sku_name(sku), tier=sku)
updated_resource.sku = full_sku
updated_resource.sku = sku
update_service_sku = True

resource = client.services.get(resource_group, name)
Expand Down
Loading