From 5bb5710b0b0bbada03cbbb35bc5884b1ab1b30b4 Mon Sep 17 00:00:00 2001 From: Tanyi Chen Date: Fri, 22 Jul 2022 15:44:38 +0800 Subject: [PATCH] [Service Connector] `az webapp connection create`: Add `--store-connstr` to support webapp connection string (#23288) * add store_in_connection_string parameter * fix linter * add test * record test * change logging to logger --- .../serviceconnector/_params.py | 12 + .../serviceconnector/_resource_config.py | 4 + .../serviceconnector/custom.py | 20 +- .../test_webapp_sql_connection_string.yaml | 680 ++++++++++++++++++ .../latest/test_webpp_connection_scenario.py | 47 +- 5 files changed, 760 insertions(+), 3 deletions(-) create mode 100644 src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/recordings/test_webapp_sql_connection_string.yaml diff --git a/src/azure-cli/azure/cli/command_modules/serviceconnector/_params.py b/src/azure-cli/azure/cli/command_modules/serviceconnector/_params.py index 806731ea471..fdf3810672b 100644 --- a/src/azure-cli/azure/cli/command_modules/serviceconnector/_params.py +++ b/src/azure-cli/azure/cli/command_modules/serviceconnector/_params.py @@ -17,6 +17,7 @@ SOURCE_RESOURCES_PARAMS, SOURCE_RESOURCES_CREATE_PARAMS, TARGET_RESOURCES_PARAMS, + TARGET_RESOURCES_CONNECTION_STRING, AUTH_TYPE_PARAMS, SUPPORTED_AUTH_TYPE, SUPPORTED_CLIENT_TYPE, @@ -147,6 +148,15 @@ def add_vnet_block(context, target): help='Connect target service by private endpoint. ' 'The private endpoint in source virtual network must be created ahead.') + def add_connection_string_argument(context, source, target): + if source == RESOURCE.WebApp and target in TARGET_RESOURCES_CONNECTION_STRING: + context.argument('store_in_connection_string', options_list=['--store-connstr'], + arg_type=get_three_state_flag(), default=False, is_preview=True, + help='Store configuration into connection string, ' + 'only could be used together with dotnet client_type') + else: + context.ignore('store_in_connection_string') + def add_confluent_kafka_argument(context): context.argument('bootstrap_server', options_list=['--bootstrap-server'], help='Kafka bootstrap server url') context.argument('kafka_key', options_list=['--kafka-key'], help='Kafka API-Key (key)') @@ -194,6 +204,7 @@ def add_confluent_kafka_argument(context): add_new_addon_argument(c, source, target) add_secret_store_argument(c) add_vnet_block(c, target) + add_connection_string_argument(c, source, target) with self.argument_context('{} connection update {}'.format(source.value, target.value)) as c: add_client_type_argument(c, source, target) add_connection_name_argument(c, source) @@ -201,6 +212,7 @@ def add_confluent_kafka_argument(context): add_auth_block(c, source, target) add_secret_store_argument(c) add_vnet_block(c, target) + add_connection_string_argument(c, source, target) # special target resource: independent implementation target = RESOURCE.ConfluentKafka diff --git a/src/azure-cli/azure/cli/command_modules/serviceconnector/_resource_config.py b/src/azure-cli/azure/cli/command_modules/serviceconnector/_resource_config.py index 8f84b66a9ce..7fc10420157 100644 --- a/src/azure-cli/azure/cli/command_modules/serviceconnector/_resource_config.py +++ b/src/azure-cli/azure/cli/command_modules/serviceconnector/_resource_config.py @@ -60,6 +60,7 @@ class AUTH_TYPE(Enum): # The dict defines the client types class CLIENT_TYPE(Enum): Dotnet = 'dotnet' + DotnetConnectionString = 'dotnet-connectionString' Java = 'java' Nodejs = 'nodejs' Python = 'python' @@ -81,6 +82,9 @@ class CLIENT_TYPE(Enum): # The target resources using user token TARGET_RESOURCES_USERTOKEN = [RESOURCE.PostgresFlexible, RESOURCE.MysqlFlexible, RESOURCE.KeyVault] +# The target resources could be set to connection string +TARGET_RESOURCES_CONNECTION_STRING = [RESOURCE.Sql, RESOURCE.Mysql, RESOURCE.MysqlFlexible, RESOURCE.Postgres, RESOURCE.PostgresFlexible] + # The dict defines the resource id pattern of source resources. SOURCE_RESOURCES = { RESOURCE.WebApp: '/subscriptions/{subscription}/resourceGroups/{source_resource_group}/providers/Microsoft.Web/sites/{site}', diff --git a/src/azure-cli/azure/cli/command_modules/serviceconnector/custom.py b/src/azure-cli/azure/cli/command_modules/serviceconnector/custom.py index 7757fafc607..009942b1584 100644 --- a/src/azure-cli/azure/cli/command_modules/serviceconnector/custom.py +++ b/src/azure-cli/azure/cli/command_modules/serviceconnector/custom.py @@ -13,6 +13,7 @@ AzureResponseError ) from ._resource_config import ( + CLIENT_TYPE, SUPPORTED_AUTH_TYPE, SUPPORTED_CLIENT_TYPE, TARGET_RESOURCES @@ -147,7 +148,7 @@ def connection_validate(cmd, client, return auto_register(client.begin_validate, resource_uri=source_id, linker_name=connection_name) -def connection_create(cmd, client, # pylint: disable=too-many-locals +def connection_create(cmd, client, # pylint: disable=too-many-locals disable=too-many-statements connection_name=None, client_type=None, source_resource_group=None, source_id=None, target_resource_group=None, target_id=None, @@ -157,6 +158,7 @@ def connection_create(cmd, client, # pylint: disable=too-many-locals key_vault_id=None, service_endpoint=None, private_endpoint=None, + store_in_connection_string=False, new_addon=False, no_wait=False, cluster=None, scope=None, enable_csi=False, # Resource.KubernetesCluster site=None, # Resource.WebApp @@ -190,6 +192,12 @@ def connection_create(cmd, client, # pylint: disable=too-many-locals raise ValidationError('Only one auth info is needed') auth_info = all_auth_info[0] if len(all_auth_info) == 1 else None + if store_in_connection_string: + if client_type == CLIENT_TYPE.Dotnet.value: + client_type = CLIENT_TYPE.DotnetConnectionString.value + else: + logger.warning('client_type is not dotnet, ignore "--store-in-connection-string"') + parameters = { 'target_service': { "type": "AzureResource", @@ -271,6 +279,7 @@ def connection_update(cmd, client, # pylint: disable=too-many-locals key_vault_id=None, service_endpoint=None, private_endpoint=None, + store_in_connection_string=False, no_wait=False, scope=None, cluster=None, enable_csi=False, # Resource.Kubernetes @@ -311,13 +320,20 @@ def connection_update(cmd, client, # pylint: disable=too-many-locals if linker.get('secretStore') and linker.get('secretStore').get('keyVaultId'): key_vault_id = key_vault_id or linker.get('secretStore').get('keyVaultId') + client_type = client_type or linker.get('clientType') + if store_in_connection_string: + if client_type == CLIENT_TYPE.Dotnet.value: + client_type = CLIENT_TYPE.DotnetConnectionString.value + else: + logger.warning('client_type is not dotnet, ignore "--store-in-connection-string"') + parameters = { 'target_service': linker.get('targetService'), 'auth_info': auth_info, 'secret_store': { 'key_vault_id': key_vault_id, }, - 'client_type': client_type or linker.get('clientType'), + 'client_type': client_type, # scope can be updated in container app while cannot be updated in aks due to some limitations 'scope': scope or linker.get('scope') } diff --git a/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/recordings/test_webapp_sql_connection_string.yaml b/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/recordings/test_webapp_sql_connection_string.yaml new file mode 100644 index 00000000000..faa30e49161 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/recordings/test_webapp_sql_connection_string.yaml @@ -0,0 +1,680 @@ +interactions: +- request: + body: '' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - 0 + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) msrest/0.7.0 + msrest_azure/0.6.4 azure-keyvault/7.0 Azure-SDK-For-Python + accept-language: + - en-US + method: GET + uri: https://cupertino-kv-test.vault.azure.net/secrets/TestDbPassword/?api-version=7.0 + response: + body: + string: '{"error": {"code": "Unauthorized", "message": "AKV10000: Request is + missing a Bearer or PoP token."}}' + headers: + cache-control: + - no-cache + content-length: + - '101' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:18:58 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + www-authenticate: + - Bearer authorization="https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47", + resource="https://vault.azure.net" + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=20.239.19.14;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - eastus + x-ms-keyvault-service-version: + - 1.9.472.2 + status: + code: 401 + message: Unauthorized +- request: + body: '' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - 0 + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) msrest/0.7.0 + msrest_azure/0.6.4 azure-keyvault/7.0 Azure-SDK-For-Python + accept-language: + - en-US + method: GET + uri: https://cupertino-kv-test.vault.azure.net/secrets/TestDbPassword/?api-version=7.0 + response: + body: + string: '{"value": "microsoft123!", "id": "https://cupertino-kv-test.vault.azure.net/secrets/TestDbPassword/e6c944984acc4f7dab51acf30b3d19cc", + "attributes": {"enabled": true, "created": 1607518360, "updated": 1607518360, + "recoveryLevel": "Recoverable+Purgeable"}}' + headers: + cache-control: + - no-cache + content-length: + - '254' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:18:59 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=20.239.19.14;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - eastus + x-ms-keyvault-service-version: + - 1.9.472.2 + status: + code: 200 + message: OK +- request: + body: '{"properties": {"targetService": {"type": "AzureResource", "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test"}, + "authInfo": {"authType": "secret", "name": "servicelinker", "secretInfo": {"secretType": + "rawValue", "value": "microsoft123!"}}, "clientType": "dotnet-connectionString", + "secretStore": {}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection create sql + Connection: + - keep-alive + Content-Length: + - '429' + Content-Type: + - application/json + ParameterSetName: + - --connection --source-id --target-id --secret --client-type --store-connstr + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:01.0460759Z"}, + "properties": {"provisioningState": "Accepted", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "vNetSolution": null, "clientType": "dotnet-connectionString", "secretStore": + {"keyVaultId": null}, "scope": null}}' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/8bcf0d85-734e-4d2a-9606-421497e9dce0*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + cache-control: + - no-cache + content-length: + - '1039' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:00 GMT + etag: + - '"00007a74-0000-0100-0000-62d8b7950000"' + expires: + - '-1' + mise-correlation-id: + - 71580583-c330-4a51-9004-cda6e1ebeb74 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection create sql + Connection: + - keep-alive + ParameterSetName: + - --connection --source-id --target-id --secret --client-type --store-connstr + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/8bcf0d85-734e-4d2a-9606-421497e9dce0*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/8bcf0d85-734e-4d2a-9606-421497e9dce0*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "name": "8bcf0d85-734e-4d2a-9606-421497e9dce0*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "status": "Succeeded", "startTime": "2022-07-21T02:19:01.2737514Z", "endTime": + "2022-07-21T02:19:09.3914075Z", "properties": {"Message": "Deny public network + access is set to yes. Please confirm you are using private endpoint connection + to access target resource."}}' + headers: + cache-control: + - no-cache + content-length: + - '830' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:31 GMT + etag: + - '"00000842-0000-0100-0000-62d8b79d0000"' + expires: + - '-1' + pragma: + - no-cache + 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: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection create sql + Connection: + - keep-alive + ParameterSetName: + - --connection --source-id --target-id --secret --client-type --store-connstr + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:01.0460759Z"}, + "properties": {"provisioningState": "Succeeded", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "clientType": "dotnet-connectionString", "scope": null, "vNetSolution": null, + "secretStore": {"keyVaultId": null}}}' + headers: + cache-control: + - no-cache + content-length: + - '1040' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:31 GMT + etag: + - '"00008174-0000-0100-0000-62d8b79d0000"' + expires: + - '-1' + mise-correlation-id: + - dad63849-c519-49a6-bafa-a24807523803 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection list + Connection: + - keep-alive + ParameterSetName: + - --source-id + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers?api-version=2022-05-01 + response: + body: + string: '{"value": [{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:01.0460759Z"}, + "properties": {"provisioningState": "Succeeded", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "clientType": "dotnet-connectionString", "scope": null, "vNetSolution": null, + "secretStore": {"keyVaultId": null}}}]}' + headers: + cache-control: + - no-cache + content-length: + - '1053' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:34 GMT + expires: + - '-1' + mise-correlation-id: + - c46d2aad-5aec-4eaf-be2f-4f391a95926b + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection update sql + Connection: + - keep-alive + ParameterSetName: + - --id --client-type --store-connstr --secret + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:01.0460759Z"}, + "properties": {"provisioningState": "Succeeded", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "clientType": "dotnet-connectionString", "scope": null, "vNetSolution": null, + "secretStore": {"keyVaultId": null}}}' + headers: + cache-control: + - no-cache + content-length: + - '1040' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:35 GMT + etag: + - '"00008174-0000-0100-0000-62d8b79d0000"' + expires: + - '-1' + mise-correlation-id: + - 6d0b930c-bf9f-42c0-ac58-0d00bbf92fd5 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + status: + code: 200 + message: OK +- request: + body: '{"properties": {"targetService": {"type": "AzureResource", "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test"}, + "authInfo": {"authType": "secret", "name": "servicelinker", "secretInfo": {"secretType": + "rawValue", "value": "microsoft123!"}}, "clientType": "dotnet-connectionString", + "secretStore": {}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection update sql + Connection: + - keep-alive + Content-Length: + - '429' + Content-Type: + - application/json + ParameterSetName: + - --id --client-type --store-connstr --secret + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:36.4489399Z"}, + "properties": {"provisioningState": "Accepted", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "vNetSolution": null, "clientType": "dotnet-connectionString", "secretStore": + {"keyVaultId": null}, "scope": null}}' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/86ff8c05-68dd-4281-8d5b-18ceac32c8bc*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + cache-control: + - no-cache + content-length: + - '1039' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:19:36 GMT + etag: + - '"0000a674-0000-0100-0000-62d8b7b80000"' + expires: + - '-1' + mise-correlation-id: + - 54c3a77d-acbb-4c4b-9761-a8db27054d4a + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection update sql + Connection: + - keep-alive + ParameterSetName: + - --id --client-type --store-connstr --secret + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/86ff8c05-68dd-4281-8d5b-18ceac32c8bc*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/86ff8c05-68dd-4281-8d5b-18ceac32c8bc*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "name": "86ff8c05-68dd-4281-8d5b-18ceac32c8bc*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "status": "Succeeded", "startTime": "2022-07-21T02:19:36.6182672Z", "endTime": + "2022-07-21T02:19:41.899941Z", "properties": {"Message": "Deny public network + access is set to yes. Please confirm you are using private endpoint connection + to access target resource."}}' + headers: + cache-control: + - no-cache + content-length: + - '829' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:20:06 GMT + etag: + - '"00002942-0000-0100-0000-62d8b7bd0000"' + expires: + - '-1' + pragma: + - no-cache + 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: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection update sql + Connection: + - keep-alive + ParameterSetName: + - --id --client-type --store-connstr --secret + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "name": "testconn", "type": "microsoft.servicelinker/linkers", "systemData": + {"createdBy": "tanchen@microsoft.com", "createdByType": "User", "createdAt": + "2022-07-21T02:19:01.0460759Z", "lastModifiedBy": "tanchen@microsoft.com", + "lastModifiedByType": "User", "lastModifiedAt": "2022-07-21T02:19:36.4489399Z"}, + "properties": {"provisioningState": "Succeeded", "targetService": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Sql/servers/servicelinker-sql/databases/handler-test", + "resourceProperties": null, "type": "AzureResource"}, "authInfo": {"name": + "servicelinker", "secretInfo": {"secretType": "rawValue"}, "authType": "secret"}, + "clientType": "dotnet-connectionString", "scope": null, "vNetSolution": null, + "secretStore": {"keyVaultId": null}}}' + headers: + cache-control: + - no-cache + content-length: + - '1040' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:20:07 GMT + etag: + - '"0000af74-0000-0100-0000-62d8b7bd0000"' + expires: + - '-1' + mise-correlation-id: + - 6488a068-2e11-4789-8839-1555ea950cc7 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - --id --yes + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn?api-version=2022-05-01 + response: + body: + string: 'null' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/bdb12937-5749-405f-ac4a-0d946d91a339*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + cache-control: + - no-cache + content-length: + - '4' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:20:12 GMT + etag: + - '"0000cb74-0000-0100-0000-62d8b7dc0000"' + expires: + - '-1' + location: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/bdb12937-5749-405f-ac4a-0d946d91a339*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + mise-correlation-id: + - 141fda5a-f3a3-4390-a4ff-e85be8929aa4 + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-providerhub-traffic: + - 'True' + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + CommandName: + - webapp connection delete + Connection: + - keep-alive + ParameterSetName: + - --id --yes + User-Agent: + - AZURECLI/2.38.0 azsdk-python-mgmt-servicelinker/1.0.0 Python/3.8.13 (Linux-5.4.0-1074-azure-x86_64-with-glibc2.2.5) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/bdb12937-5749-405f-ac4a-0d946d91a339*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0?api-version=2022-05-01 + response: + body: + string: '{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.ServiceLinker/locations/EASTUS/operationStatuses/bdb12937-5749-405f-ac4a-0d946d91a339*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "name": "bdb12937-5749-405f-ac4a-0d946d91a339*F712114A38F364B5CAB427C8E5BC23507E99B0D32E8EDFB0E4134B38ABF46FB0", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/servicelinker-test-linux-group/providers/Microsoft.Web/sites/servicelinker-sql-app/providers/Microsoft.ServiceLinker/linkers/testconn", + "status": "Succeeded", "startTime": "2022-07-21T02:20:12.3230753Z", "endTime": + "2022-07-21T02:20:18.5009251Z", "properties": null}' + headers: + cache-control: + - no-cache + content-length: + - '694' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 21 Jul 2022 02:20:42 GMT + etag: + - '"00003b42-0000-0100-0000-62d8b7e20000"' + expires: + - '-1' + pragma: + - no-cache + 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/serviceconnector/tests/latest/test_webpp_connection_scenario.py b/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/test_webpp_connection_scenario.py index d46c0fb6035..438b166cd61 100644 --- a/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/test_webpp_connection_scenario.py +++ b/src/azure-cli/azure/cli/command_modules/serviceconnector/tests/latest/test_webpp_connection_scenario.py @@ -768,7 +768,7 @@ def test_webapp_mysqlflexible_e2e(self): password = self.cmd('keyvault secret show --vault-name cupertino-kv-test -n TestDbPassword')\ .get_output_in_json().get('value') keyvaultUri = "https://cupertino-kv-test.vault.azure.net/secrets/TestDbPassword" - + # prepare params name = 'testconn' source_id = SOURCE_RESOURCES.get(RESOURCE.WebApp).format(**self.kwargs) @@ -915,6 +915,51 @@ def test_webapp_sql_e2e(self): self.cmd('webapp connection delete --id {} --yes'.format(connection_id)) + @record_only() + def test_webapp_sql_connection_string(self): + self.kwargs.update({ + 'subscription': get_subscription_id(self.cli_ctx), + 'source_resource_group': 'servicelinker-test-linux-group', + 'target_resource_group': 'servicelinker-test-linux-group', + 'site': 'servicelinker-sql-app', + 'server': 'servicelinker-sql', + 'database': 'handler-test' + }) + + # prepare password + user = 'servicelinker' + password = self.cmd('keyvault secret show --vault-name cupertino-kv-test -n TestDbPassword')\ + .get_output_in_json().get('value') + + # prepare params + name = 'testconn' + source_id = SOURCE_RESOURCES.get(RESOURCE.WebApp).format(**self.kwargs) + target_id = TARGET_RESOURCES.get(RESOURCE.Sql).format(**self.kwargs) + + # create connection + self.cmd('webapp connection create sql --connection {} --source-id {} --target-id {} --secret name={} secret={} ' + '--client-type dotnet --store-connstr'.format(name, source_id, target_id, user, password)) + + # list connection + connections = self.cmd( + 'webapp connection list --source-id {}'.format(source_id), + checks = [ + self.check('length(@)', 1), + self.check('[0].authInfo.authType', 'secret'), + self.check('[0].clientType', 'dotnet-connectionString') + ] + ).get_output_in_json() + connection_id = connections[0].get('id') + + # update connection + self.cmd('webapp connection update sql --id {} --client-type dotnet --store-connstr ' + '--secret name={} secret={}'.format(connection_id, user, password), + checks = [ self.check('clientType', 'dotnet-connectionString') ]) + + # delete connection + self.cmd('webapp connection delete --id {} --yes'.format(connection_id)) + + @record_only() def test_webapp_storageblob_e2e(self): self.kwargs.update({