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

Expose sku and managed identity for GA #11795

Merged
merged 24 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b6db469
expose sku and managed identity feature
shenmuxiaosen Jan 6, 2020
341fc00
Expose features for GA
shenmuxiaosen Jan 8, 2020
a3251b7
fix styling issues
shenmuxiaosen Jan 8, 2020
a764e67
update user agent version
shenmuxiaosen Jan 8, 2020
b0bf46d
dedup input identities
shenmuxiaosen Jan 9, 2020
1ff77a2
add test cases for user assgined identity
shenmuxiaosen Jan 9, 2020
249ddfe
Merge remote-tracking branch 'upstream/dev' into user/shuai/gafeature
shenmuxiaosen Jan 10, 2020
9431bf6
remove duplicate code
shenmuxiaosen Jan 10, 2020
3ce80fb
Merge remote-tracking branch 'upstream/dev' into user/shuai/gafeature
shenmuxiaosen Jan 14, 2020
dd24ba7
revise identity validator
shenmuxiaosen Jan 14, 2020
0a850ea
add default for identities
shenmuxiaosen Jan 14, 2020
5e8c32d
remove unnecessary import
shenmuxiaosen Jan 14, 2020
40fd252
hard code default value for identity
shenmuxiaosen Jan 15, 2020
ad60331
make identity argument take empty list
shenmuxiaosen Jan 15, 2020
08a473b
Merge remote-tracking branch 'upstream/dev' into user/shuai/gafeature
shenmuxiaosen Jan 16, 2020
1dfc586
resolve conflict
shenmuxiaosen Jan 16, 2020
f8f5e4e
merge dev
shenmuxiaosen Jan 17, 2020
1d8c382
merge dev
shenmuxiaosen Jan 21, 2020
1585a52
merge conflict
shenmuxiaosen Jan 21, 2020
0756703
merge dev
shenmuxiaosen Jan 21, 2020
f7b79fe
update tests
shenmuxiaosen Jan 21, 2020
4b7e76e
fix styling issue
shenmuxiaosen Jan 21, 2020
c2f6f01
revise help message for --identities
shenmuxiaosen Jan 21, 2020
ddb9c64
remove multiple spaces
shenmuxiaosen Jan 21, 2020
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
6 changes: 6 additions & 0 deletions src/azure-cli/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
Release History
===============

**AppConfig**
Juliehzl marked this conversation as resolved.
Show resolved Hide resolved

* Remove preview tag for most commands.
* Expose sku modification for configuration store.
* Add command group for managed identity.

2.0.79
++++++

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class StatusCodes:
class Versions:
"""Constants of versions.
"""
SDKVersion = '1.0.0'
SDKVersion = '2.0.0'
ApiVersion = '1.0'


Expand Down
18 changes: 15 additions & 3 deletions src/azure-cli/azure/cli/command_modules/appconfig/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ def configstore_output_format(result):
return _output_format(result, _configstore_format_group)


def configstore_identity_format(result):
return _output_format(result, _configstore_identity_format_group)


def configstore_credential_format(result):
return _output_format(result, _configstore_credential_format_group)

Expand Down Expand Up @@ -47,16 +51,24 @@ def _configstore_format_group(item):
sku = ""

return OrderedDict([
('CREATIONDATE', _format_datetime(_get_value(item, 'creationDate'))),
('CREATION DATE', _format_datetime(_get_value(item, 'creationDate'))),
('ENDPOINT', _get_value(item, 'endpoint')),
('LOCATION', _get_value(item, 'location')),
('NAME', _get_value(item, 'name')),
('PROVISIONINGSTATE', _get_value(item, 'provisioningState')),
('RESOURCEGROUP', _get_value(item, 'resourceGroup')),
('PROVISIONING STATE', _get_value(item, 'provisioningState')),
('RESOURCE GROUP', _get_value(item, 'resourceGroup')),
('SKU', sku)
])


def _configstore_identity_format_group(item):
return OrderedDict([
('PRINCIPAL ID', _format_datetime(_get_value(item, 'principalId'))),
('TENANT ID', _get_value(item, 'tenantId')),
('TYPE', _get_value(item, 'type'))
])


def _configstore_credential_format_group(item):
return OrderedDict([
('CONNECTION STRING', _get_value(item, 'connectionString')),
Expand Down
47 changes: 44 additions & 3 deletions src/azure-cli/azure/cli/command_modules/appconfig/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,52 @@
type: command
short-summary: Create an App Configuration.
examples:
- name: Create an App Configuration with name, location and resource group.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus
- name: Create an App Configuration with name, location, sku and resource group.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --sku Standard
- name: Create an App Configuration with name, location, sku and resource group with system assigned identity.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --sku Standard --assign-identity [system]
"""

helps['appconfig identity'] = """
type: group
short-summary: Managed identities for App Configurations.
"""

helps['appconfig identity assign'] = """
type: command
short-summary: Update managed identities for an App Configuration.
examples:
- name: Enable the system-assigned identity for an existing App Configuration
text: az appconfig identity assign -g MyResourceGroup -n MyAppConfiguration
- name: Assign a user-assigned managed identity for an existing App Configuration
text: az appconfig identity assign -g MyResourceGroup -n MyAppConfiguration --identities "/subscriptions/<SUBSCRIPTON ID>/resourcegroups/<RESOURCEGROUP>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity"
- name: Assign both system-assigned and user assigned identities for an existing App Configuration
text: az appconfig identity assign -g MyResourceGroup -n MyAppConfiguration --identities [system] "/subscriptions/<SUBSCRIPTON ID>/resourcegroups/<RESOURCEGROUP>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity"
"""

helps['appconfig identity remove'] = """
type: command
short-summary: Remove managed identities for an App Configuration.
examples:
- name: Remove the system-assigned identity from a App Configuration.
text: az appconfig identity remove -g MyResourceGroup -n MyAppConfiguration
- name: Remove a user assigned identity from a App Configuration.
text: az appconfig identity remove -g MyResourceGroup -n MyAppConfiguration --identities "/subscriptions/<SUBSCRIPTON ID>/resourcegroups/<RESOURCEGROUP>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity"
- name: Remove all identities from an App Configuration.
text: az appconfig identity remove -g MyResourceGroup -n MyAppConfiguration --identities [all]
"""

helps['appconfig identity show'] = """
type: command
short-summary: Display managed identities for an App Configuration.
examples:
- name: Display managed identities for a task.
text: az appconfig identity show -g MyResourceGroup -n MyAppConfiguration
"""

helps['appconfig credential'] = """
type: group
short-summary: Manage credentials for App Configurations
short-summary: Manage credentials for App Configurations.
"""

helps['appconfig credential list'] = """
Expand Down Expand Up @@ -207,6 +246,8 @@
examples:
- name: Update tags of an App Configuration
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --tags key1=value1 key2=value2
- name: Upgrade sku of an App Configuration to standard
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --sku Standard
"""

helps['appconfig feature'] = """
Expand Down
21 changes: 16 additions & 5 deletions src/azure-cli/azure/cli/command_modules/appconfig/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
validate_export, validate_import,
validate_import_depth, validate_query_fields,
validate_feature_query_fields, validate_filter_parameters,
validate_separator, validate_secret_identifier)
validate_separator, validate_secret_identifier,
validate_assigned_identity, validate_identities)


def load_arguments(self, _):
Expand Down Expand Up @@ -63,14 +64,24 @@ def load_arguments(self, _):
c.argument('top', arg_type=top_arg_type)
c.argument('all_', options_list=['--all'], action='store_true', help="List all items.")
c.argument('fields', arg_type=fields_arg_type)
c.argument('sku', help='The sku of App Configuration', arg_type=get_enum_type(['free', 'standard']))

with self.argument_context('appconfig create') as c:
c.argument('location', options_list=['--location', '-l'], arg_type=get_location_type(self.cli_ctx), validator=get_default_location_from_resource_group)
c.ignore('sku')
c.argument('assign_identity', nargs='*', validator=validate_assigned_identity, is_preview=True, help="Accept system or user assigned identities separated by spaces. Use '[system]' to refer system assigned identity, or a resource id to refer user assigned identity. Check out help for more examples")
shenmuxiaosen marked this conversation as resolved.
Show resolved Hide resolved

with self.argument_context('appconfig update') as c:
c.argument('tags', arg_type=tags_type)

with self.argument_context('appconfig identity') as c:
Copy link
Member

@avanigupta avanigupta Jan 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add params and help for appconfig identity show #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all commands under "appconfig identity" command group will inherit self.argument_context('appconfig identity'), similarly it will also inherit self.argument_context('appconfig'). Since identity show doesn't introduce arguments with different specification, we don't need to specify it here.


In reply to: 364511385 [](ancestors = 364511385)

c.argument('identities', nargs='*', validator=validate_identities)
Juliehzl marked this conversation as resolved.
Show resolved Hide resolved

with self.argument_context('appconfig identity assign') as c:
c.argument('identities', help="Accept system or user assigned identities separated by spaces. Use '[system]' to refer system assigned identity, or a resource id to refer user assigned identity. Check out help for more examples")
shenmuxiaosen marked this conversation as resolved.
Show resolved Hide resolved

with self.argument_context('appconfig identity remove') as c:
c.argument('identities', help="Accept system or user assigned identities separated by spaces. Use '[system]' to refer system assigned identity, '[all]' for all identities or a resource id to refer user assigned identity. Check out help for more examples")

with self.argument_context('appconfig credential regenerate') as c:
c.argument('id_', options_list=['--id'], help='Id of the key to be regenerated. Can be found using az appconfig credential list command.')

Expand All @@ -79,7 +90,7 @@ def load_arguments(self, _):
c.argument('prefix', help="This prefix will be appended to the front of imported keys. Prefix will be ignored for feature flags.")
c.argument('source', options_list=['--source', '-s'], arg_type=get_enum_type(['file', 'appconfig', 'appservice']), validator=validate_import, help="The source of importing. Note that importing feature flags from appservice is not supported.")
c.argument('yes', help="Do not prompt for preview.")
c.argument('skip_features', help="Import only key values and exclude all feature flags. By default, all feature flags will be imported from file or appconfig. Not applicable for appservice.", arg_type=get_three_state_flag())
c.argument('skip_features', is_preview=True, help="Import only key values and exclude all feature flags. By default, all feature flags will be imported from file or appconfig. Not applicable for appservice.", arg_type=get_three_state_flag())

with self.argument_context('appconfig kv import', arg_group='File') as c:
c.argument('path', help='Local configuration file path. Required for file arguments.')
Expand All @@ -103,15 +114,15 @@ def load_arguments(self, _):
c.argument('key', help='If no key specified, return all keys by default. Support star sign as filters, for instance abc* means keys with abc as prefix. Similarly, *abc and *abc* are also supported. Key filtering not applicable for feature flags. By default, all feature flags with specified label will be exported.')
c.argument('destination', options_list=['--destination', '-d'], arg_type=get_enum_type(['file', 'appconfig', 'appservice']), validator=validate_export, help="The destination of exporting. Note that exporting feature flags to appservice is not supported.")
c.argument('yes', help="Do not prompt for preview.")
c.argument('skip_features', help="Export only key values and exclude all feature flags. By default, all features with the specified label will be exported to file or appconfig. Not applicable for appservice.", arg_type=get_three_state_flag())
c.argument('skip_features', is_preview=True, help="Export only key values and exclude all feature flags. By default, all features with the specified label will be exported to file or appconfig. Not applicable for appservice.", arg_type=get_three_state_flag())

with self.argument_context('appconfig kv export', arg_group='File') as c:
c.argument('path', help='Local configuration file path. Required for file arguments.')
c.argument('format_', options_list=['--format'], arg_type=get_enum_type(['json', 'yaml', 'properties']), help='File format exporting to. Required for file arguments. Currently, feature flags are not supported in properties format.')
c.argument('depth', validator=validate_import_depth, help="Depth for flattening the json or yaml file to key-value pairs. Flatten to the deepest level by default. Not appicable for property files or feature flags.")
# bypass cli allowed values limition
c.argument('separator', validator=validate_separator, help="Delimiter for flattening the json or yaml file to key-value pairs. Required for importing hierarchical structure. Separator will be ignored for property files and feature flags. Supported values: '.', ',', ';', '-', '_', '__', '/', ':' ")
c.argument('naming_convention', arg_type=get_enum_type(['pascal', 'camel', 'underscore', 'hyphen']), help='Naming convention to be used for "Feature Management" section of file. Example: pascal = FeatureManagement, camel = featureManagement, underscore = feature_management, hyphen = feature-management.')
c.argument('naming_convention', is_preview=True, arg_type=get_enum_type(['pascal', 'camel', 'underscore', 'hyphen']), help='Naming convention to be used for "Feature Management" section of file. Example: pascal = FeatureManagement, camel = featureManagement, underscore = feature_management, hyphen = feature-management.')

with self.argument_context('appconfig kv export', arg_group='AppConfig') as c:
c.argument('dest_name', help='The name of the destination App Configuration.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,26 @@ def validate_filter_parameter(string):
return result


def validate_assigned_identity(namespace):
if namespace.assign_identity:
from msrestazure.tools import is_valid_resource_id

namespace.assign_identity = set(namespace.assign_identity)
for identity in namespace.assign_identity:
if identity != '[system]' and not is_valid_resource_id(identity):
raise CLIError("Invalid identity '{}'. Use '[system]' to refer system assigned identity, or a resource id to refer user assigned identity.".format(identity))


def validate_identities(namespace):
if namespace.identities:
from msrestazure.tools import is_valid_resource_id

namespace.identities = set(namespace.identities)
for identity in namespace.identities:
if identity != '[system]' and identity != '[all]' and not is_valid_resource_id(identity):
Copy link
Member

@avanigupta avanigupta Jan 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and identity != '[all]' [](start = 37, length = 24)

This case should only be valid for the remove identity command right? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. there is a validation in assign_identity to exlcude '[all]'. We can have two validators for assign and remove identity, but they will be very similar except for '[all]' check.


In reply to: 364514597 [](ancestors = 364514597)

shenmuxiaosen marked this conversation as resolved.
Show resolved Hide resolved
raise CLIError("Invalid identity '{}'. Use '[system]' to refer system assigned identity '[all]' for all identities, or a resource id to refer user assigned identity.".format(identity))


def validate_secret_identifier(namespace):
""" Validate the format of keyvault reference secret identifier """
from azure.keyvault.key_vault_id import KeyVaultIdentifier
Expand Down
27 changes: 19 additions & 8 deletions src/azure-cli/azure/cli/command_modules/appconfig/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from ._client_factory import cf_configstore, cf_configstore_operations
from ._format import (configstore_credential_format,
configstore_identity_format,
configstore_output_format,
keyvalue_entry_format,
featureflag_entry_format,
Expand All @@ -21,6 +22,12 @@ def load_command_table(self, _):
client_factory=cf_configstore
)

configstore_identity_util = CliCommandType(
operations_tmpl='azure.cli.command_modules.appconfig.custom#{}',
table_transformer=configstore_identity_format,
client_factory=cf_configstore
)

configstore_credential_util = CliCommandType(
operations_tmpl='azure.cli.command_modules.appconfig.custom#{}',
table_transformer=configstore_credential_format,
Expand All @@ -44,21 +51,23 @@ def get_custom_sdk(custom_module, client_factory, table_transformer):
)

# Management Plane Commands
with self.command_group('appconfig', configstore_custom_util, is_preview=True) as g:
with self.command_group('appconfig', configstore_custom_util) as g:
g.command('create', 'create_configstore')
g.command('delete', 'delete_configstore')
g.command('update', 'update_configstore')
g.command('list', 'list_configstore')
g.command('show', 'show_configstore')
g.generic_update_command('update',
getter_name='configstore_update_get',
setter_name='configstore_update_set',
custom_func_name='configstore_update_custom')
g.command('update', 'update_configstore')

with self.command_group('appconfig credential', configstore_credential_util) as g:
g.command('list', 'list_credential')
g.command('regenerate', 'regenerate_credential')

with self.command_group('appconfig identity', configstore_identity_util, is_preview=True) as g:
g.command('assign', 'assign_managed_identity')
g.command('remove', 'remove_managed_identity')
g.command('show', 'show_managed_identity')

with self.command_group('appconfig revision', configstore_keyvalue_util) as g:
g.command('list', 'list_revision')

Expand All @@ -73,13 +82,14 @@ def get_custom_sdk(custom_module, client_factory, table_transformer):
g.command('restore', 'restore_key')
g.command('import', 'import_config')
g.command('export', 'export_config')
g.command('set-keyvault', 'set_keyvault')
g.command('set-keyvault', 'set_keyvault', is_preview=True)

# FeatureManagement Commands
with self.command_group('appconfig feature',
custom_command_type=get_custom_sdk('feature',
cf_configstore_operations,
featureflag_entry_format)) as g:
featureflag_entry_format),
is_preview=True) as g:
g.custom_command('set', 'set_feature')
g.custom_command('delete', 'delete_feature')
g.custom_command('show', 'show_feature')
Expand All @@ -92,7 +102,8 @@ def get_custom_sdk(custom_module, client_factory, table_transformer):
with self.command_group('appconfig feature filter',
custom_command_type=get_custom_sdk('feature',
cf_configstore_operations,
featurefilter_entry_format)) as g:
featurefilter_entry_format),
is_preview=True) as g:
g.custom_command('add', 'add_filter')
g.custom_command('delete', 'delete_filter')
g.custom_command('show', 'show_filter')
Expand Down
Loading