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

Add ACS related commands #18

Merged
merged 1 commit into from
Aug 12, 2021
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
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