diff --git a/src/azure-cli/HISTORY.rst b/src/azure-cli/HISTORY.rst index 45f31f22d42..01ef03a03e6 100644 --- a/src/azure-cli/HISTORY.rst +++ b/src/azure-cli/HISTORY.rst @@ -23,13 +23,14 @@ Release History * GA Release Large File Shares property for storage account create and update command * GA Release User Delegation SAS token Support +* Add new commands `az storage account blob-service-properties show` and `az storage account blob-service-properties update --enable-change-feed` to manage blob service properties for storage account. 2.0.77 ++++++ **ACR** -* Deprecated paramater `--branch` from acr task create/update +* Deprecated parameter `--branch` from acr task create/update **Azure Red Hat OpenShift** diff --git a/src/azure-cli/azure/cli/command_modules/storage/_client_factory.py b/src/azure-cli/azure/cli/command_modules/storage/_client_factory.py index bd2da2e2dc9..522d0f66312 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_client_factory.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_client_factory.py @@ -155,5 +155,9 @@ def cf_blob_container_mgmt(cli_ctx, _): return storage_client_factory(cli_ctx).blob_containers +def cf_mgmt_blob_services(cli_ctx, _): + return storage_client_factory(cli_ctx).blob_services + + def cf_blob_data_gen_update(cli_ctx, kwargs): return blob_data_service_factory(cli_ctx, kwargs.copy()) diff --git a/src/azure-cli/azure/cli/command_modules/storage/_help.py b/src/azure-cli/azure/cli/command_modules/storage/_help.py index 00dc873cd7b..48fb1c1eb8f 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_help.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_help.py @@ -17,6 +17,38 @@ short-summary: Manage storage accounts. """ +helps['storage account blob-service-properties'] = """ +type: group +short-summary: Manage the properties of a storage account's blob service. +""" + +helps['storage account blob-service-properties show'] = """ +type: command +short-summary: Show the properties of a storage account's blob service. +long-summary: > + Show the properties of a storage account's blob service, including + properties for Storage Analytics and CORS (Cross-Origin Resource + Sharing) rules. +examples: + - name: Show the properties of the storage account 'MyStorageAccount' in resource group 'MyResourceGroup'. + text: az storage account blob-service-properties show -n MyStorageAccount -g MyResourceGroup +""" + +helps['storage account blob-service-properties update'] = """ +type: command +short-summary: Update the properties of a storage account's blob service. +long-summary: > + Update the properties of a storage account's blob service, including + properties for Storage Analytics and CORS (Cross-Origin Resource + Sharing) rules. But currently we only support enabling or disabling change feed for a storage account's blob service. +parameters: + - name: --enable-change-feed + short-summary: 'Indicate whether change feed event logging is enabled. If it is true, you enable the storage account to begin capturing changes. The default value is true. You can see more details in https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal#register-by-using-azure-cli' +examples: + - name: Enable the change feed for the storage account 'MyStorageAccount' in resource group 'MyResourceGroup'. + text: az storage account blob-service-properties update --enable-change-feed true -n MyStorageAccount -g MyResourceGroup +""" + helps['storage account create'] = """ type: command short-summary: Create a storage account. diff --git a/src/azure-cli/azure/cli/command_modules/storage/_params.py b/src/azure-cli/azure/cli/command_modules/storage/_params.py index 85eb4b41603..1dd5b0d5c94 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_params.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_params.py @@ -240,6 +240,17 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem c.argument('vnet_name', help='Name of a virtual network.', validator=validate_subnet) c.argument('action', help='The action of virtual network rule.') + with self.argument_context('storage account blob-service-properties show', + resource_type=ResourceType.MGMT_STORAGE) as c: + c.argument('account_name', acct_name_type, id_part=None) + c.argument('resource_group_name', required=False, validator=process_resource_group) + + with self.argument_context('storage account blob-service-properties update', + resource_type=ResourceType.MGMT_STORAGE) as c: + c.argument('account_name', acct_name_type, id_part=None) + c.argument('resource_group_name', required=False, validator=process_resource_group) + c.argument('enable_change_feed', arg_type=get_three_state_flag(), min_api='2019-04-01') + with self.argument_context('storage account generate-sas') as c: t_account_permissions = self.get_sdk('common.models#AccountPermissions') c.register_sas_arguments() diff --git a/src/azure-cli/azure/cli/command_modules/storage/commands.py b/src/azure-cli/azure/cli/command_modules/storage/commands.py index 5f21fb72456..3dd7f9e402c 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/commands.py +++ b/src/azure-cli/azure/cli/command_modules/storage/commands.py @@ -9,7 +9,8 @@ cloud_storage_account_service_factory, multi_service_properties_factory, cf_mgmt_policy, - cf_blob_data_gen_update, cf_sa_for_keys) + cf_blob_data_gen_update, cf_sa_for_keys, + cf_mgmt_blob_services) from azure.cli.command_modules.storage.sdkutil import cosmosdb_table_exists from azure.cli.command_modules.storage._format import transform_immutability_policy from azure.cli.core.commands import CliCommandType @@ -24,6 +25,12 @@ def load_command_table(self, _): # pylint: disable=too-many-locals, too-many-st resource_type=ResourceType.MGMT_STORAGE ) + blob_service_mgmt_sdk = CliCommandType( + operations_tmpl='azure.mgmt.storage.operations#BlobServicesOperations.{}', + client_factory=cf_mgmt_blob_services, + resource_type=ResourceType.MGMT_STORAGE + ) + storage_account_sdk_keys = CliCommandType( operations_tmpl='azure.mgmt.storage.operations#StorageAccountsOperations.{}', client_factory=cf_sa_for_keys, @@ -116,6 +123,15 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT g.custom_command('list', 'list_network_rules') g.custom_command('remove', 'remove_network_rule') + with self.command_group('storage account blob-service-properties', blob_service_mgmt_sdk, + custom_command_type=storage_account_custom_type, + resource_type=ResourceType.MGMT_STORAGE, min_api='2018-07-01', is_preview=True) as g: + g.show_command('show', 'get_service_properties') + g.generic_update_command('update', + getter_name='get_service_properties', + setter_name='set_service_properties', + custom_func_name='update_blob_service_properties') + with self.command_group('storage logging', get_custom_sdk('logging', multi_service_properties_factory)) as g: from ._transformers import transform_logging_list_output g.storage_command('update', 'set_logging') diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/account.py b/src/azure-cli/azure/cli/command_modules/storage/operations/account.py index 94a32ed8dfc..eeabd16cbb5 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/operations/account.py +++ b/src/azure-cli/azure/cli/command_modules/storage/operations/account.py @@ -335,3 +335,10 @@ def update_management_policies(client, resource_group_name, account_name, parame if parameters: parameters = parameters.policy return client.create_or_update(resource_group_name, account_name, policy=parameters) + + +# TODO: support updating other properties besides 'enable_change_feed' +def update_blob_service_properties(cmd, instance, enable_change_feed=None): + if enable_change_feed is not None: + instance.change_feed = cmd.get_models('ChangeFeed')(enabled=enable_change_feed) + return instance diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_account_update_change_feed.yaml b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_account_update_change_feed.yaml new file mode 100644 index 00000000000..ec3cf2424b3 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_account_update_change_feed.yaml @@ -0,0 +1,366 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '395' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:00:55 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: '{"properties": {"cors": {"corsRules": []}, "deleteRetentionPolicy": {"enabled": + false}, "changeFeed": {"enabled": true}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + Content-Length: + - '121' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":true},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '425' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:00:57 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":true},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '425' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:00:57 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: '{"properties": {"cors": {"corsRules": []}, "deleteRetentionPolicy": {"enabled": + false}, "changeFeed": {"enabled": false}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + Content-Length: + - '122' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":false},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '426' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:00:59 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1198' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":false},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '426' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:00:59 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: '{"properties": {"cors": {"corsRules": []}, "deleteRetentionPolicy": {"enabled": + false}, "changeFeed": {"enabled": true}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties update + Connection: + - keep-alive + Content-Length: + - '121' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - --enable-change-feed -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":true},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '425' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:01:01 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - storage account blob-service-properties show + Connection: + - keep-alive + ParameterSetName: + - -n -g + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.10 msrest_azure/0.6.2 + azure-mgmt-storage/5.0.0 Azure-SDK-For-Python AZURECLI/2.0.77 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default?api-version=2019-04-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/blobServices/default","name":"default","type":"Microsoft.Storage/storageAccounts/blobServices","properties":{"changeFeed":{"enabled":true},"cors":{"corsRules":[]},"deleteRetentionPolicy":{"enabled":false}}}' + headers: + cache-control: + - no-cache + content-length: + - '425' + content-type: + - application/json + date: + - Fri, 06 Dec 2019 02:01:01 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py index f5213686837..ebb11bbc8d5 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py @@ -625,3 +625,21 @@ def test_storage_account_revoke_delegation_keys(self, resource_group, storage_ac time.sleep(15) # By-design, it takes some time for RBAC system propagated with graph object change self.cmd('storage blob show -c {container} -n {blob} --account-name {account} --sas-token {blob_sas}', expect_failure=True) + + +@api_version_constraint(ResourceType.MGMT_STORAGE, min_api='2019-04-01') +class BlobServicePropertiesTests(StorageScenarioMixin, ScenarioTest): + @ResourceGroupPreparer() + @StorageAccountPreparer() + def test_storage_account_update_change_feed(self): + result = self.cmd('storage account blob-service-properties update --enable-change-feed true -n {sa} -g {rg}').get_output_in_json() + self.assertEqual(result['changeFeed']['enabled'], True) + + result = self.cmd('storage account blob-service-properties update --enable-change-feed false -n {sa} -g {rg}').get_output_in_json() + self.assertEqual(result['changeFeed']['enabled'], False) + + result = self.cmd('storage account blob-service-properties update --enable-change-feed -n {sa} -g {rg}').get_output_in_json() + self.assertEqual(result['changeFeed']['enabled'], True) + + result = self.cmd('storage account blob-service-properties show -n {sa} -g {rg}').get_output_in_json() + self.assertEqual(result['changeFeed']['enabled'], True)