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

[MSFT/Mason Chen] Add CLI for enterprise buildpacks binding #20

Merged
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a5940d9
add buildpacks binding in commands.py
jiec-msft Aug 12, 2021
4ca0af2
add buildpacks binding type enum
jiec-msft Aug 12, 2021
a177b61
add buildpacks binding parameter helps
jiec-msft Aug 12, 2021
380b9d7
add buildpacks binding command helps
jiec-msft Aug 12, 2021
8b40ba8
enhance parameter definition
jiec-msft Aug 12, 2021
9e7f9a6
add stubs for create/set/show/delete parameters
jiec-msft Aug 12, 2021
c449e3e
add buildpacks binding name validator
jiec-msft Aug 12, 2021
cb223f6
add parameter to sub command stud
jiec-msft Aug 12, 2021
21f615e
fix for buildpacks binding name regex string
jiec-msft Aug 12, 2021
653ea95
add empty lines
jiec-msft Aug 12, 2021
21dba44
add properties and secrets validator
jiec-msft Aug 12, 2021
d85f884
add help info for command group
jiec-msft Aug 12, 2021
7674782
fix for buildpacks binding properties and secrets validator
jiec-msft Aug 12, 2021
5f40a40
make buildpacks binding operation concrete
jiec-msft Aug 12, 2021
ff465a3
remove print
jiec-msft Aug 12, 2021
367e7aa
add only support enterprise validator
jiec-msft Aug 13, 2021
eacd28b
and newline at end of file for exception enterprise
jiec-msft Aug 13, 2021
d27d9de
add newline for following methods in _enterprise
jiec-msft Aug 13, 2021
6a6693a
fix style check error
jiec-msft Aug 13, 2021
7493e28
stylecheck fix: remove redundant backslash
jiec-msft Aug 13, 2021
43eef1f
remove unused imports
jiec-msft Aug 13, 2021
8dce3b0
add parenthesis
jiec-msft Aug 13, 2021
8532ec5
replace with CLIError
jiec-msft Aug 13, 2021
8ab5936
remove un-necessary exception
jiec-msft Aug 13, 2021
6ac0f1a
use buildpacks binding type from SDK
jiec-msft Aug 13, 2021
037c9cf
enhance buildpacks binding properties and secrets parameter, its vali…
jiec-msft Aug 13, 2021
7a42171
fix for calling to get before create/set
jiec-msft Aug 13, 2021
96173bc
remove extra Required for name param
jiec-msft Aug 13, 2021
bacbe38
replace InvalidArgumentValueError with CLIError in validators
jiec-msft Aug 13, 2021
a17582a
put length check in regex
jiec-msft Aug 13, 2021
ea1c78c
merge create and set into one and add different validators for them
jiec-msft Aug 13, 2021
eb2d5ab
enhance show command for buildpacks binding
jiec-msft Aug 13, 2021
e1f45e8
refine for delete for buildpacks binding
jiec-msft Aug 13, 2021
31c4b1d
add space
jiec-msft Aug 13, 2021
e54631d
add comment to explain buildpacks binding name format
jiec-msft Aug 13, 2021
246e18b
add SDK files for buildpacks binding
jiec-msft Aug 13, 2021
ec94e62
Merge branch 'enterprise' into masonchen/enterprise-buildpacks-binding
jiec-msft Aug 13, 2021
3cf14ef
use get_client from utils_enterprise to simplify the code
jiec-msft Aug 13, 2021
0ff695d
remove customized exception handling
jiec-msft Aug 13, 2021
03f9f29
remove un-used method
jiec-msft Aug 13, 2021
e812bf1
union create and set commands
jiec-msft Aug 13, 2021
a4710b5
fix for style check
jiec-msft Aug 13, 2021
42f450d
remove buildpacks binding name validation and delegate to RP
jiec-msft Aug 13, 2021
93c94ff
simplify argument type
jiec-msft Aug 15, 2021
516b7a1
enhance validator for create/set
jiec-msft Aug 15, 2021
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
2 changes: 2 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
DELETE_PRODUCTION_DEPLOYMENT_WARNING = "You are going to delete production deployment, the app will be inaccessible after this operation."
LOG_RUNNING_PROMPT = "This command usually takes minutes to run. Add '--verbose' parameter if needed."

DEFAULT_BUILD_SERVICE_NAME = "default"


def app_get_enterprise(cmd, client, resource_group, service, name):
app = client.apps.get(resource_group, service, name)
Expand Down
43 changes: 43 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,46 @@
- name: Unbind an app to Application Configuration Service.
text: az spring-cloud application-configuration-service unbind --app MyApp -s MyService -g MyResourceGroup
"""

helps['spring-cloud build-service buildpacks-binding'] = """
type: group
short-summary: (Enterprise Tier Only) Commands to manage Buildpacks Binding
"""

helps['spring-cloud build-service buildpacks-binding create'] = """
type: command
short-summary: Create a buildpacks binding.
examples:
- name: Create a buildpacks binding without properties or secrets.
jiec-msft marked this conversation as resolved.
Show resolved Hide resolved
text: az spring-cloud build-service buildpacks-binding create --name first-binding --type ApplicationInsights
- name: Create a buildpacks binding with only secrets.
text: az spring-cloud build-service buildpacks-binding create --name first-binding --type ApplicationInsights --secrets k1=v1 k2=v2
- name: Create a buildpacks binding with only properties.
text: az spring-cloud build-service buildpacks-binding create --name first-binding --type ApplicationInsights --properties a=b c=d
- name: Create a buildpacks binding with properties and secrets.
text: az spring-cloud build-service buildpacks-binding create --name first-binding --type ApplicationInsights --properties a=b c=d --secrets k1=v1 k2=v2
"""

helps['spring-cloud build-service buildpacks-binding set'] = """
type: command
short-summary: Set a buildpacks binding.
examples:
- name: Set a buildpacks binding with properties and secrets.
text: az spring-cloud build-service buildpacks-binding set --name first-binding --type ApplicationInsights --properties a=b c=d --secrets k1=v1 k2=v2
"""

helps['spring-cloud build-service buildpacks-binding show'] = """
type: command
short-summary: Show a buildpacks binding, the secrets will be masked.
examples:
- name: Show a buildpacks binding.
text: az spring-cloud build-service buildpacks-binding show --name first-binding
"""

helps['spring-cloud build-service buildpacks-binding delete'] = """
type: command
short-summary: Delete a buildpacks binding.
examples:
- name: Delete a buildpacks binding.
text: az spring-cloud build-service buildpacks-binding delete --name first-binding
"""
46 changes: 45 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,33 @@
validate_vnet, validate_vnet_required_parameters, validate_node_resource_group,
validate_tracing_parameters, validate_app_insights_parameters, validate_java_agent_parameters,
validate_instance_count)
from ._validators_enterprise import (only_support_enterprise, validate_config_file_patterns, validate_cpu, validate_memory,
from ._validators_enterprise import (validate_config_file_patterns, validate_cpu, validate_memory,
validate_buildpacks_binding_properties,
validate_buildpacks_binding_secrets, only_support_enterprise,
enterprise_only_and_binding_not_exist, enterprise_only_and_binding_exist,
validate_git_uri, validate_acs_patterns)
from ._utils import ApiType

from .vendored_sdks.appplatform.v2020_07_01.models import RuntimeVersion, TestKeyType
from .vendored_sdks.appplatform.v2022_05_01_preview.models \
import _app_platform_management_client_enums as v20220501_preview_AppPlatformEnums


name_type = CLIArgumentType(options_list=[
'--name', '-n'], help='The primary resource name', validator=validate_name)
env_type = CLIArgumentType(
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')
buildpacks_binding_properties_type = CLIArgumentType(help='Non-sensitive properties for launchProperties. '
jiec-msft marked this conversation as resolved.
Show resolved Hide resolved
'Format "key[=value]".',
nargs='*',
validator=validate_buildpacks_binding_properties)
buildpacks_binding_secrets_type = CLIArgumentType(help='Sensitive properties for launchProperties. '
'Once put, it will be encrypted and never return to user. '
'Format "key[=value]".',
nargs="*",
validator=validate_buildpacks_binding_secrets)


# pylint: disable=too-many-statements
Expand Down Expand Up @@ -321,3 +336,32 @@ def prepare_logs_argument(c):
'spring-cloud application-configuration-service git repo remove']:
with self.argument_context(scope) as c:
c.argument('name', help="Required unique name to label each item of git configs.")

for scope in ['spring-cloud build-service buildpacks-binding create',
'spring-cloud build-service buildpacks-binding set']:
jiec-msft marked this conversation as resolved.
Show resolved Hide resolved
with self.argument_context(scope) as c:
c.argument('type',
arg_type=get_enum_type(v20220501_preview_AppPlatformEnums.BindingType),
help='Required type for buildpacks binding.')
c.argument('properties',
buildpacks_binding_properties_type)
c.argument('secrets',
buildpacks_binding_secrets_type)

for scope in ['spring-cloud build-service buildpacks-binding create',
'spring-cloud build-service buildpacks-binding set',
'spring-cloud build-service buildpacks-binding show',
'spring-cloud build-service buildpacks-binding delete']:
with self.argument_context(scope) as c:
c.argument('name', help='Name for buildpacks binding.')

for scope in ['spring-cloud build-service buildpacks-binding show',
'spring-cloud build-service buildpacks-binding delete']:
with self.argument_context(scope) as c:
c.argument('service', service_name_type, validator=only_support_enterprise)

with self.argument_context('spring-cloud build-service buildpacks-binding create') as c:
c.argument('service', service_name_type, validator=enterprise_only_and_binding_not_exist)

with self.argument_context('spring-cloud build-service buildpacks-binding set') as c:
c.argument('service', service_name_type, validator=enterprise_only_and_binding_exist)
65 changes: 64 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_validators_enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

from re import match
from azure.cli.core.util import CLIError
from azure.cli.core.commands.validators import validate_tag
from azure.core.exceptions import ResourceNotFoundError
from knack.log import get_logger
from ._enterprise import DEFAULT_BUILD_SERVICE_NAME
from ._resource_quantity import (
validate_cpu as validate_and_normalize_cpu,
validate_memory as validate_and_normalize_memory)
from ._util_enterprise import (
is_enterprise_tier
is_enterprise_tier, get_client
)


Expand Down Expand Up @@ -75,3 +78,63 @@ def _is_valid_profile_name(profile):
def _is_valid_app_and_profile_name(pattern):
parts = pattern.split('/')
return len(parts) == 2 and _is_valid_app_name(parts[0]) and _is_valid_profile_name(parts[1])


def validate_buildpacks_binding_properties(namespace):
""" Extracts multiple space-separated properties in key[=value] format """
if isinstance(namespace.properties, list):
properties_dict = {}
for item in namespace.properties:
properties_dict.update(validate_tag(item))
namespace.properties = properties_dict


def validate_buildpacks_binding_secrets(namespace):
""" Extracts multiple space-separated secrets in key[=value] format """
if isinstance(namespace.secrets, list):
secrets_dict = {}
for item in namespace.secrets:
secrets_dict.update(validate_tag(item))
namespace.secrets = secrets_dict


def enterprise_only_and_binding_not_exist(cmd, namespace):
only_support_enterprise(cmd, namespace)
yuwzho marked this conversation as resolved.
Show resolved Hide resolved
client = get_client(cmd)
_validate_binding_not_exists(client,
namespace.resource_group,
namespace.service,
namespace.name)


def enterprise_only_and_binding_exist(cmd, namespace):
only_support_enterprise(cmd, namespace)
client = get_client(cmd)
_validate_binding_exists(client,
namespace.resource_group,
namespace.service,
namespace.name)


def _validate_binding_not_exists(client, resource_group, service, binding_name):
try:
binding_resource = client.buildpacks_binding.get(resource_group,
yuwzho marked this conversation as resolved.
Show resolved Hide resolved
service,
DEFAULT_BUILD_SERVICE_NAME,
binding_name)
if binding_resource is not None:
raise CLIError('Buildpacks Binding {} already exists '
'in resource group {}, service {}. You can edit it by set command.'
.format(binding_name, resource_group, service))
except ResourceNotFoundError:
# Excepted case
pass


def _validate_binding_exists(client, resource_group, service, binding_name):
try:
client.buildpacks_binding.get(resource_group, service, DEFAULT_BUILD_SERVICE_NAME, binding_name)
except ResourceNotFoundError:
raise CLIError('Buildpacks Binding {} does not exist '
'in resource group {}, service {}. Please create before set.'
.format(binding_name, resource_group, service))
34 changes: 34 additions & 0 deletions src/spring-cloud/azext_spring_cloud/buildpacks_binding.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 ._enterprise import DEFAULT_BUILD_SERVICE_NAME
from .vendored_sdks.appplatform.v2022_05_01_preview import models


def create_or_update_buildpacks_binding(cmd, client, resource_group, service,
name, type, properties=None, secrets=None):
binding_resource = _build_buildpacks_binding_resource(type, properties, secrets)
return client.buildpacks_binding.create_or_update(resource_group,
service,
DEFAULT_BUILD_SERVICE_NAME,
name,
binding_resource)


def buildpacks_binding_show(cmd, client, resource_group, service, name):
return client.buildpacks_binding.get(resource_group, service, DEFAULT_BUILD_SERVICE_NAME, name)


jiec-msft marked this conversation as resolved.
Show resolved Hide resolved
def buildpacks_binding_delete(cmd, client, resource_group, service, name):
return client.buildpacks_binding.delete(resource_group, service, DEFAULT_BUILD_SERVICE_NAME, name)


def _build_buildpacks_binding_resource(binding_type, properties_dict, secrets_dict):
launch_properties = models.BuildpacksBindingLaunchProperties(properties=properties_dict,
secrets=secrets_dict)
binding_properties = models.BuildpacksBindingProperties(binding_type=binding_type,
launch_properties=launch_properties)
return models.BuildpacksBindingResource(properties=binding_properties)
14 changes: 14 additions & 0 deletions src/spring-cloud/azext_spring_cloud/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ def load_command_table(self, _):
client_factory=cf_spring_cloud_enterprise
)

buildpacks_binding_cmd_group = CliCommandType(
operations_tmpl="azext_spring_cloud.buildpacks_binding#{}",
client_factory=cf_spring_cloud_enterprise
)

with self.command_group('spring-cloud', client_factory=cf_app_services,
exception_handler=handle_asc_exception) as g:
g.custom_command('create', 'spring_cloud_create', supports_no_wait=True, client_factory=cf_spring_cloud)
Expand Down Expand Up @@ -171,5 +176,14 @@ def load_command_table(self, _):
g.custom_command('remove', 'application_configuration_service_git_remove')
g.custom_command('list', 'application_configuration_service_git_list')

with self.command_group('spring-cloud build-service buildpacks-binding',
custom_command_type=buildpacks_binding_cmd_group,
exception_handler=handle_asc_exception) as g:
# create and set commands are differentiate by their parameter validators
g.custom_command('create', 'create_or_update_buildpacks_binding')
g.custom_command('set', 'create_or_update_buildpacks_binding')
g.custom_command('show', 'buildpacks_binding_show')
g.custom_command('delete', 'buildpacks_binding_delete')

with self.command_group('spring-cloud', exception_handler=handle_asc_exception):
pass
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,19 @@ def build_service(self):
raise ValueError("API version {} does not have operation group 'build_service'".format(api_version))
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

@property
def buildpacks_binding(self):
"""Instance depends on the API version:

* 2022-05-01-preview: :class:`BuildpacksBindingOperations<azure.mgmt.appplatform.v2022_05_01_preview.operations.BuildpacksBindingOperations>`
"""
api_version = self._get_api_version('buildpacks_binding')
if api_version == '2022-05-01-preview':
from .v2022_05_01_preview.operations import BuildpacksBindingOperations as OperationClass
else:
raise ValueError("API version {} does not have operation group 'buildpacks_binding'".format(api_version))
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

@property
def certificates(self):
"""Instance depends on the API version:
Expand Down Expand Up @@ -360,6 +373,32 @@ def runtime_versions(self):
raise ValueError("API version {} does not have operation group 'runtime_versions'".format(api_version))
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

@property
def service(self):
"""Instance depends on the API version:

* 2022-05-01-preview: :class:`ServiceOperations<azure.mgmt.appplatform.v2022_05_01_preview.operations.ServiceOperations>`
"""
api_version = self._get_api_version('service')
if api_version == '2022-05-01-preview':
from .v2022_05_01_preview.operations import ServiceOperations as OperationClass
else:
raise ValueError("API version {} does not have operation group 'service'".format(api_version))
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

@property
def service_registries(self):
"""Instance depends on the API version:

* 2022-05-01-preview: :class:`ServiceRegistriesOperations<azure.mgmt.appplatform.v2022_05_01_preview.operations.ServiceRegistriesOperations>`
"""
api_version = self._get_api_version('service_registries')
if api_version == '2022-05-01-preview':
from .v2022_05_01_preview.operations import ServiceRegistriesOperations as OperationClass
else:
raise ValueError("API version {} does not have operation group 'service_registries'".format(api_version))
return OperationClass(self._client, self._config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

@property
def services(self):
"""Instance depends on the API version:
Expand Down
Loading