Skip to content

Commit

Permalink
Add ACS related commands (Azure#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
ninpan-ms authored Aug 12, 2021
1 parent 9b6ae7b commit d0251da
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
55 changes: 55 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,58 @@
- name: Unbind an app to Service Registry.
text: az spring-cloud service-registry unbind --app MyApp -s MyService -g MyResourceGroup
"""

helps['spring-cloud application-configuration-service show'] = """
type: command
short-summary: Show provisioning status, runtime status and settings of Application Configuration Service.
"""

helps['spring-cloud application-configuration-service clear'] = """
type: command
short-summary: Reset all Application Configuration Service settings.
"""

helps['spring-cloud application-configuration-service git repo add'] = """
type: command
short-summary: Add an item of git property to Application Configuration Service settings.
examples:
- name: Add an item of git property.
text: az spring-cloud application-configuration-service git repo add -s MyService -g MyResourceGroup --name MyName --patterns MyPattern --uri https://MyURI --label master
"""

helps['spring-cloud application-configuration-service git repo update'] = """
type: command
short-summary: Update an existing item of git property to Application Configuration Service settings.
examples:
- name: Update an item of git property.
text: az spring-cloud application-configuration-service git repo update -s MyService -g MyResourceGroup --name MyName --patterns MyPattern
"""

helps['spring-cloud application-configuration-service git repo remove'] = """
type: command
short-summary: Delete an existing item of git property to Application Configuration Service settings.
examples:
- name: Delete an item of git property.
text: az spring-cloud application-configuration-service git repo remove -s MyService -g MyResourceGroup --name MyName
"""

helps['spring-cloud application-configuration-service git repo list'] = """
type: command
short-summary: List all git settings of Application Configuration Service.
"""

helps['spring-cloud application-configuration-service bind'] = """
type: command
short-summary: Bind app to Application Configuration Service.
examples:
- name: Bind an app to Application Configuration Service.
text: az spring-cloud application-configuration-service bind --app MyApp -s MyService -g MyResourceGroup
"""

helps['spring-cloud application-configuration-service unbind'] = """
type: command
short-summary: Unbind app to Application Configuration Service.
examples:
- name: Unbind an app to Application Configuration Service.
text: az spring-cloud application-configuration-service unbind --app MyApp -s MyService -g MyResourceGroup
"""
27 changes: 27 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,30 @@ def prepare_logs_argument(c):

with self.argument_context('spring-cloud service-registry unbind') as c:
c.argument('app', app_name_type, help='Name of app.', validator=validate_app_name)

with self.argument_context('spring-cloud application-configuration-service bind') as c:
c.argument('app', app_name_type, help='Name of app.', validator=validate_app_name)

with self.argument_context('spring-cloud application-configuration-service unbind') as c:
c.argument('app', app_name_type, help='Name of app.', validator=validate_app_name)

for scope in ['spring-cloud application-configuration-service git repo add',
'spring-cloud application-configuration-service git repo update']:
with self.argument_context(scope) as c:
c.argument('patterns',
help="Required patterns used to search in Git repositories. For each pattern, use format like {application} or {application}/{profile} instead of {application}-{profile}.yml, and separate them by comma."),
c.argument('uri', help="Required Git URI."),
c.argument('label', help="Required branch name to search in the Git repository."),
c.argument('search_paths', help='search_paths of the added config, use , as delimiter for multiple paths.')
c.argument('username', help='Username of the added config.')
c.argument('password', help='Password of the added config.')
c.argument('host_key', help='Host key of the added config.')
c.argument('host_key_algorithm', help='Host key algorithm of the added config.')
c.argument('private_key', help='Private_key of the added config.')
c.argument('strict_host_key_checking', help='Strict_host_key_checking of the added config.')

for scope in ['spring-cloud application-configuration-service git repo add',
'spring-cloud application-configuration-service git repo update',
'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.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=unused-argument, logging-format-interpolation, protected-access, wrong-import-order, too-many-lines
import json

from ._enterprise import app_get_enterprise
from ._util_enterprise import (is_enterprise_tier, get_client)
from .vendored_sdks.appplatform.v2022_05_01_preview import models as models
from azure.cli.core.commands import cached_put
from azure.cli.core.util import sdk_no_wait
from knack.log import get_logger
from knack.util import CLIError

APPLICATION_CONFIGURATION_SERVICE_NAME = "ApplicationConfigurationService"

logger = get_logger(__name__)

def application_configuration_service_show(cmd, client, service, resource_group):
return client.configuration_services.get(resource_group, service)


def application_configuration_service_clear(cmd, client, service, resource_group):
properties = models.ConfigurationServiceGitProperty()
acs_resource = models.ConfigurationServiceResource(properties=properties)
return client.configuration_services.begin_create_or_update(resource_group, service, acs_resource)


def application_configuration_service_git_add(cmd, client, service, resource_group,
name, patterns, uri, label,
search_paths=None,
username=None,
password=None,
host_key=None,
host_key_algorithm=None,
private_key=None,
strict_host_key_checking=None,
no_wait=False):
repo = models.ConfigurationServiceGitRepository(name=name, patterns=patterns, uri=uri, label=label)
repo = _replace_repo_with_input(repo, patterns, uri, label, search_paths, username, password, host_key, host_key_algorithm, private_key, strict_host_key_checking)

acs_resource = _get_or_default_acs_resource(client, resource_group, service)
repos = acs_resource.properties.settings.git_property.repositories
if next((r for r in repos if r.name == name), None) is not None:
raise CLIError("Repo '{}' already exists.".format(name))
repos.append(repo)
acs_resource.properties.settings.git_property.repositories = repos

_validate_acs_settings(client, resource_group, service, acs_resource.properties.settings)

logger.warning("[2/2] Adding item to Application Configuration Service settings, (this operation can take a while to complete)")
return sdk_no_wait(no_wait, client.configuration_services.begin_create_or_update, resource_group, service, acs_resource)


def application_configuration_service_git_update(cmd, client, service, resource_group, name,
patterns=None,
uri=None,
label=None,
search_paths=None,
username=None,
password=None,
host_key=None,
host_key_algorithm=None,
private_key=None,
strict_host_key_checking=None,
no_wait=False):
acs_resource = _get_or_default_acs_resource(client, resource_group, service)

repo = _get_existing_repo(acs_resource.properties.settings.git_property.repositories, name)
repo = _replace_repo_with_input(repo, patterns, uri, label, search_paths, username, password, host_key, host_key_algorithm, private_key, strict_host_key_checking)

_validate_acs_settings(client, resource_group, service, acs_resource.properties.settings)

logger.warning("[2/2] Updating item of Application Configuration Service settings, (this operation can take a while to complete)")
return sdk_no_wait(no_wait, client.configuration_services.begin_create_or_update, resource_group, service, acs_resource)


def application_configuration_service_git_remove(cmd, client, service, resource_group, name, no_wait=False):
acs_resource = _get_or_default_acs_resource(acs_resource)

repo = _get_existing_repo(acs_resource.properties.settings.git_property.repositories, name)
acs_resource.properties.settings.git_property.repositories.remove(repo)

_validate_acs_settings(client, resource_group, service, acs_resource.properties.settings)

logger.warning("[2/2] Removing item of Application Configuration Service settings, (this operation can take a while to complete)")
return sdk_no_wait(no_wait, client.configuration_services.begin_create_or_update, resource_group, service, acs_resource)


def application_configuration_service_git_list(cmd, client, service, resource_group):
acs_resource = client.configuration_services.get(resource_group, service)
acs_settings = acs_resource.properties.settings

if not acs_settings or not acs_settings.git_property or not acs_settings.git_property.repositories:
raise CLIError("Repos not found.")

return acs_settings.git_property.repositories


def application_configuration_service_bind(cmd, client, service, resource_group, app):
_acs_bind_or_unbind_app(cmd, client, service, resource_group, app, True)


def application_configuration_service_unbind(cmd, client, service, resource_group, app):
_acs_bind_or_unbind_app(cmd, client, service, resource_group, app, False)


def _acs_bind_or_unbind_app(cmd, client, service, resource_group, app_name, enabled):
app = client.apps.get(resource_group, service, app_name)
app.properties.addon_configs = _get_app_addon_configs_with_acs(app.properties.addon_configs)

if app.properties.addon_configs[APPLICATION_CONFIGURATION_SERVICE_NAME].enabled == enabled:
logger.warning('App "{}" has been {}binded'.format(app_name, '' if enabled else 'un'))
return

app.properties.addon_configs[APPLICATION_CONFIGURATION_SERVICE_NAME].enabled = enabled
return client.apps.begin_update(resource_group, service, app_name, app)


def _get_app_addon_configs_with_acs(addon_configs):
if addon_configs is None:
addon_configs = {}
if addon_configs.get(APPLICATION_CONFIGURATION_SERVICE_NAME) is None:
addon_configs[APPLICATION_CONFIGURATION_SERVICE_NAME] = models.AddonProfile()
return addon_configs


def _replace_repo_with_input(repo, patterns, uri, label, search_paths, username, password, host_key, host_key_algorithm, private_key, strict_host_key_checking):
if patterns:
patterns = patterns.split(",")
if search_paths:
search_paths = search_paths.split(",")

repo.patterns = patterns or repo.patterns
repo.uri = uri or repo.uri
repo.label = label or repo.label
repo.search_paths = search_paths or repo.search_paths
repo.username = username or repo.username
repo.password = password or repo.password
repo.host_key = host_key or repo.host_key
repo.host_key_algorithm = host_key_algorithm or repo.host_key_algorithm
repo.private_key = private_key or repo.private_key
repo.strict_host_key_checking = strict_host_key_checking or repo.strict_host_key_checking
return repo


def _get_existing_repo(repos, name):
repo = next((r for r in repos if r.name == name), None)
if not repo:
raise CLIError("Repo '{}' not found.".format(name))
return repo


def _get_or_default_acs_resource(client, resource_group, service):
acs_resource = client.configuration_services.get(resource_group, service)
if acs_resource is None:
acs_resource = models.ConfigurationServiceResource()
acs_resource.properties = _get_acs_properties(acs_resource.properties)
return acs_resource


def _get_acs_properties(properties):
if properties is None:
properties = models.ConfigurationServiceProperties()
properties.settings = _get_acs_settings(properties.settings)
return properties


def _get_acs_settings(acs_settings):
if acs_settings is None:
acs_settings = models.ConfigurationServiceSettings()
acs_settings.git_property = _get_acs_git_property(acs_settings.git_property)
return acs_settings


def _get_acs_git_property(git_property):
if git_property is None:
git_property = models.ConfigurationServiceGitProperty()
git_property.repositories = _get_acs_repos(git_property.repositories)
return git_property


def _get_acs_repos(repos):
return repos or []


def _validate_acs_settings(client, resource_group, service, acs_settings):
logger.warning("[1/2] Validating Application Configuration Service settings")

if acs_settings is None or acs_settings.git_property is None:
return

try:
result = sdk_no_wait(False, client.configuration_services.begin_validate, resource_group, service, acs_settings).result()
except Exception as err: # pylint: disable=broad-except
raise CLIError("{0}. You may raise a support ticket if needed by the following link: https://docs.microsoft.com/azure/spring-cloud/spring-cloud-faq?pivots=programming-language-java#how-can-i-provide-feedback-and-report-issues".format(err))

if result is not None and result.git_property_validation_result is not None:
git_result = result.git_property_validation_result
if not git_result.is_valid:
validation_result = git_result.git_repos_validation_result
filter_result = [{'name':x.name, 'messages':x.messages} for x in validation_result if len(x.messages) > 0]
raise CLIError("Application Configuration Service settings contain errors.\n{}".format(json.dumps(filter_result, indent=2)))
21 changes: 21 additions & 0 deletions src/spring-cloud/azext_spring_cloud/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ def load_command_table(self, _):
client_factory=cf_spring_cloud_enterprise
)

application_configuration_service_cmd_group = CliCommandType(
operations_tmpl='azext_spring_cloud.application_configuration_service#{}',
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 @@ -150,5 +155,21 @@ def load_command_table(self, _):
g.custom_command('bind', 'service_registry_bind')
g.custom_command('unbind', 'service_registry_unbind')

with self.command_group('spring-cloud application-configuration-service',
custom_command_type=application_configuration_service_cmd_group,
exception_handler=handle_asc_exception) as g:
g.custom_command('clear', 'application_configuration_service_clear')
g.custom_command('show', 'application_configuration_service_show')
g.custom_command('bind', 'application_configuration_service_bind')
g.custom_command('unbind', 'application_configuration_service_unbind')

with self.command_group('spring-cloud application-configuration-service git repo',
custom_command_type=application_configuration_service_cmd_group,
exception_handler=handle_asc_exception) as g:
g.custom_command('add', 'application_configuration_service_git_add')
g.custom_command('update', 'application_configuration_service_git_update')
g.custom_command('remove', 'application_configuration_service_git_remove')
g.custom_command('list', 'application_configuration_service_git_list')

with self.command_group('spring-cloud', exception_handler=handle_asc_exception):
pass

0 comments on commit d0251da

Please sign in to comment.