diff --git a/src/apic-extension/azext_apic_extension/tests/latest/constants.py b/src/apic-extension/azext_apic_extension/tests/latest/constants.py index f0dfd012c5a..8971cda555f 100644 --- a/src/apic-extension/azext_apic_extension/tests/latest/constants.py +++ b/src/apic-extension/azext_apic_extension/tests/latest/constants.py @@ -7,4 +7,8 @@ TEST_REGION = "eastus" # to set USERASSIGNED_IDENTITY, refer to https://learn.microsoft.com/en-us/azure/api-center/import-api-management-apis?tabs=portal#option-2-import-apis-directly-from-your-api-management-instance -USERASSIGNED_IDENTITY = os.getenv('USERASSIGNED_IDENTITY') \ No newline at end of file +USERASSIGNED_IDENTITY = os.getenv('USERASSIGNED_IDENTITY') +# aws credentials KeyVault references +AWS_ACCESS_KEY_LINK = os.getenv('AWS_ACCESS_KEY_LINK') +AWS_SECRET_ACCESS_KEY_LINK = os.getenv('AWS_SECRET_ACCESS_KEY_LINK') +AWS_REGION = "us-west-2" \ No newline at end of file diff --git a/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_apim.yaml b/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_apim.yaml new file mode 100644 index 00000000000..2c739cba3ea --- /dev/null +++ b/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_apim.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"properties": {"apiSourceType": "AzureApiManagement", "azureApiManagementSource": + {"msiResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test", + "resourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiManagement/service/clitest000004"}, + "importSpecification": "always"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - apic integration create apim + Connection: + - keep-alive + Content-Length: + - '467' + Content-Type: + - application/json + ParameterSetName: + - -g -n --azure-apim -i --msi-resource-id + User-Agent: + - AZURECLI/2.67.0 azsdk-python-core/1.28.0 Python/3.11.9 (Windows-10-10.0.22631-SP0) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003?api-version=2024-06-01-preview + response: + body: + string: '{"type":"Microsoft.ApiCenter/services/workspaces/apiSources","properties":{"apiSourceType":"AzureApiManagement","apimSource":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiManagement/service/clitest000004","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"azureApiManagementSource":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiManagement/service/clitest000004","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"sourceLifecycleStage":"design","targetEnvironmentId":"/workspaces/default/environments/azure-api-management","targetLifecycleStage":"design","importSpecification":"always","linkState":{"state":"initializing","lastUpdatedOn":"2024-12-24T07:30:53.3997958Z"}},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003","name":"cli000003","systemData":{"createdAt":"2024-12-24T07:30:53.3997938Z","lastModifiedAt":"2024-12-24T07:30:53.3997919Z"}}' + headers: + api-supported-versions: + - 2023-07-01-preview, 2024-03-01, 2024-03-15-preview, 2024-06-01-preview + cache-control: + - no-cache + content-length: + - '1408' + content-type: + - application/json; charset=utf-8 + date: + - Tue, 24 Dec 2024 07:30:53 GMT + etag: + - 0a00e783-0000-3300-0000-676a632d0000 + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-global-writes: + - '11999' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-msedge-ref: + - 'Ref A: 8A292E25303F4B6F8FE86A99C399FA6B Ref B: MAA201060513045 Ref C: 2024-12-24T07:30:50Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - apic integration show + Connection: + - keep-alive + ParameterSetName: + - -g -n -i + User-Agent: + - AZURECLI/2.67.0 azsdk-python-core/1.28.0 Python/3.11.9 (Windows-10-10.0.22631-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003?api-version=2024-06-01-preview + response: + body: + string: '{"type":"Microsoft.ApiCenter/services/workspaces/apiSources","properties":{"apiSourceType":"AzureApiManagement","apimSource":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiManagement/service/clitest000004","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"azureApiManagementSource":{"resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiManagement/service/clitest000004","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"sourceLifecycleStage":"design","targetEnvironmentId":"/workspaces/default/environments/azure-api-management","targetLifecycleStage":"design","importSpecification":"always","linkState":{"state":"initializing","lastUpdatedOn":"2024-12-24T07:30:53.3997958Z"}},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003","name":"cli000003","systemData":{"createdAt":"2024-12-24T07:30:53.3997938Z","lastModifiedAt":"2024-12-24T07:30:53.3997919Z"}}' + headers: + api-supported-versions: + - 2023-07-01-preview, 2024-03-01, 2024-03-15-preview, 2024-06-01-preview + cache-control: + - no-cache + content-length: + - '1408' + content-type: + - application/json; charset=utf-8 + date: + - Tue, 24 Dec 2024 07:30:55 GMT + etag: + - 0a00e783-0000-3300-0000-676a632d0000 + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-global-reads: + - '16499' + x-msedge-ref: + - 'Ref A: EC6649C72E924E18B01BEBABEE4C3426 Ref B: MAA201060516027 Ref C: 2024-12-24T07:30:54Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +version: 1 diff --git a/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_aws.yaml b/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_aws.yaml new file mode 100644 index 00000000000..79185b7306c --- /dev/null +++ b/src/apic-extension/azext_apic_extension/tests/latest/recordings/test_integration_create_aws.yaml @@ -0,0 +1,118 @@ +interactions: +- request: + body: '{"properties": {"amazonApiGatewaySource": {"accessKey": "https://kv-canary-franktest.vault.azure.net/secrets/AccessKey", + "regionName": "us-west-2", "secretAccessKey": "https://kv-canary-franktest.vault.azure.net/secrets/SecretAccessKey"}, + "apiSourceType": "AmazonApiGateway", "importSpecification": "always"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - apic integration create aws + Connection: + - keep-alive + Content-Length: + - '309' + Content-Type: + - application/json + ParameterSetName: + - -g -n -i --aws-access-key-reference --aws-region --aws-secret-access-key-reference + User-Agent: + - AZURECLI/2.67.0 azsdk-python-core/1.28.0 Python/3.11.9 (Windows-10-10.0.22631-SP0) + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003?api-version=2024-06-01-preview + response: + body: + string: '{"type":"Microsoft.ApiCenter/services/workspaces/apiSources","properties":{"apiSourceType":"AmazonApiGateway","amazonApiGatewaySource":{"accessKey":"https://kv-canary-franktest.vault.azure.net/secrets/AccessKey","secretAccessKey":"https://kv-canary-franktest.vault.azure.net/secrets/SecretAccessKey","regionName":"us-west-2","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"sourceLifecycleStage":"design","targetEnvironmentId":"/workspaces/default/environments/amazon-api-gateway","targetLifecycleStage":"design","importSpecification":"always","linkState":{"state":"initializing","lastUpdatedOn":"2024-12-27T05:53:55.9076442Z"}},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003","name":"cli000003","systemData":{"createdAt":"2024-12-27T05:53:55.907644Z","lastModifiedAt":"2024-12-27T05:53:55.9076428Z"}}' + headers: + api-supported-versions: + - 2023-07-01-preview, 2024-03-01, 2024-03-15-preview, 2024-06-01-preview + cache-control: + - no-cache + content-length: + - '1080' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 27 Dec 2024 05:53:55 GMT + etag: + - 0f00b5e3-0000-3300-0000-676e40f30000 + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-global-writes: + - '11999' + x-ms-ratelimit-remaining-subscription-writes: + - '799' + x-msedge-ref: + - 'Ref A: D235AE0BE4F94FA2A7C867F38533C9C6 Ref B: MAA201060516009 Ref C: 2024-12-27T05:53:53Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - apic integration show + Connection: + - keep-alive + ParameterSetName: + - -g -n -i + User-Agent: + - AZURECLI/2.67.0 azsdk-python-core/1.28.0 Python/3.11.9 (Windows-10-10.0.22631-SP0) + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003?api-version=2024-06-01-preview + response: + body: + string: '{"type":"Microsoft.ApiCenter/services/workspaces/apiSources","properties":{"apiSourceType":"AmazonApiGateway","amazonApiGatewaySource":{"accessKey":"https://kv-canary-franktest.vault.azure.net/secrets/AccessKey","secretAccessKey":"https://kv-canary-franktest.vault.azure.net/secrets/SecretAccessKey","regionName":"us-west-2","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-apic-extension-cli-test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/apic-extension-cli-test"},"sourceLifecycleStage":"design","targetEnvironmentId":"/workspaces/default/environments/amazon-api-gateway","targetLifecycleStage":"design","importSpecification":"always","linkState":{"state":"syncing","lastUpdatedOn":"2024-12-27T05:53:57.0047644Z"}},"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clirg000001/providers/Microsoft.ApiCenter/services/clitest000002/workspaces/default/apiSources/cli000003","name":"cli000003","systemData":{"createdAt":"2024-12-27T05:53:55.907644Z","lastModifiedAt":"2024-12-27T05:53:57.0047642Z"}}' + headers: + api-supported-versions: + - 2023-07-01-preview, 2024-03-01, 2024-03-15-preview, 2024-06-01-preview + cache-control: + - no-cache + content-length: + - '1075' + content-type: + - application/json; charset=utf-8 + date: + - Fri, 27 Dec 2024 05:53:57 GMT + etag: + - 0f00b6e3-0000-3300-0000-676e40f50000 + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + vary: + - Accept-Encoding + x-cache: + - CONFIG_NOCACHE + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-global-reads: + - '16499' + x-msedge-ref: + - 'Ref A: C4F90FBD93284E49AC7A80530307B1ED Ref B: MAA201060513053 Ref C: 2024-12-27T05:53:56Z' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK +version: 1 diff --git a/src/apic-extension/azext_apic_extension/tests/latest/test_integration_commands.py b/src/apic-extension/azext_apic_extension/tests/latest/test_integration_commands.py new file mode 100644 index 00000000000..e17bff39d0b --- /dev/null +++ b/src/apic-extension/azext_apic_extension/tests/latest/test_integration_commands.py @@ -0,0 +1,85 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import jmespath +import collections +from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer +from azure.cli.testsdk.checkers import JMESPathCheck +from azure.cli.testsdk.exceptions import JMESPathCheckAssertionError +from .utils import ApicServicePreparer, ApimServicePreparer +from .constants import TEST_REGION, AWS_ACCESS_KEY_LINK, AWS_SECRET_ACCESS_KEY_LINK, AWS_REGION, USERASSIGNED_IDENTITY + +# override the JMESPathCheck class to support checking multiple possible values as a list +class JMESPathCheckAny(JMESPathCheck): + def __init__(self, query, expected_results, case_sensitive=True): + super().__init__(query, expected_results, case_sensitive) + if not isinstance(expected_results, list): + raise ValueError("expected_results should be a list of possible values") + + def __call__(self, execution_result): + json_value = execution_result.get_output_in_json() + actual_value = jmespath.search(self._query, json_value, jmespath.Options(collections.OrderedDict)) + if self._case_sensitive: + if actual_value not in [result for result in self._expected_result]: + raise JMESPathCheckAssertionError(self._query, self._expected_result, actual_value, execution_result.output) + else: + if actual_value.lower() not in [result.lower() for result in self._expected_result]: + raise JMESPathCheckAssertionError(self._query, self._expected_result, actual_value, execution_result.output) + +class IntegrationCommandTests(ScenarioTest): + # override the check method to support checking multiple possible values + def check(self, query, expected_results, case_sensitive=True): + query = self._apply_kwargs(query) + expected_results = self._apply_kwargs(expected_results) + + if isinstance(expected_results, list): + return JMESPathCheckAny(query, expected_results, case_sensitive) + else: + return JMESPathCheck(query, expected_results, case_sensitive) + + # TODO: change the location to TEST_REGION when the APIC resource provider is available in all regions + @ResourceGroupPreparer(name_prefix="clirg", location="centraluseuap", random_name_length=32) + @ApicServicePreparer() + @ApimServicePreparer() + def test_integration_create_apim(self): + if self.is_live: + # prepare test data + self.kwargs.update({ + 'integration_name': self.create_random_name(prefix='cli', length=8) + }) + + if self.kwargs['use_system_assigned_identity'] or not self.is_live: + self.cmd('az apic integration create apim -g {rg} -n {s} --azure-apim {apim_name} -i {integration_name}') + else: + self.cmd('az apic integration create apim -g {rg} -n {s} --azure-apim {apim_name} -i {integration_name} --msi-resource-id "{usi_id}"') + + # verify command results + self.cmd('az apic integration show -g {rg} -n {s} -i {integration_name}', checks=[ + self.check('apiSourceType', 'AzureApiManagement'), + self.check('name', '{integration_name}'), + self.check('linkState.state', list(['initializing', 'syncing'])) + ]) + + @ResourceGroupPreparer(name_prefix="clirg", location="centraluseuap", random_name_length=32) + @ApicServicePreparer(user_assigned_identity=USERASSIGNED_IDENTITY) + def test_integration_create_aws(self): + if self.is_live: + # prepare test data + self.kwargs.update({ + 'integration_name': self.create_random_name(prefix='cli', length=8), + 'usi_id': USERASSIGNED_IDENTITY, + 'access_key_link': AWS_ACCESS_KEY_LINK, + 'secret_access_key_link': AWS_SECRET_ACCESS_KEY_LINK, + 'aws_region': AWS_REGION + }) + + self.cmd('az apic integration create aws -g {rg} -n {s} -i {integration_name} --aws-access-key-reference {access_key_link} --aws-region {aws_region} --aws-secret-access-key-reference {secret_access_key_link}') + + # verify command results + self.cmd('az apic integration show -g {rg} -n {s} -i {integration_name}', checks=[ + self.check('apiSourceType', 'AmazonApiGateway'), + self.check('name', '{integration_name}'), + self.check('linkState.state', list(['initializing', 'syncing'])) + ]) diff --git a/src/apic-extension/azext_apic_extension/tests/latest/test_service_commands.py b/src/apic-extension/azext_apic_extension/tests/latest/test_service_commands.py index 8ffcc8d1dfd..3177792a5a8 100644 --- a/src/apic-extension/azext_apic_extension/tests/latest/test_service_commands.py +++ b/src/apic-extension/azext_apic_extension/tests/latest/test_service_commands.py @@ -8,11 +8,8 @@ import unittest from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer -from .utils import ApicServicePreparer -from .constants import TEST_REGION, USERASSIGNED_IDENTITY - -# if USERASSIGNED_IDENTITY is set, enable_system_assigned_identity is False, otherwise use system assigned identity -enable_system_assigned_identity = False if USERASSIGNED_IDENTITY else True +from .utils import ApicServicePreparer, ApimServicePreparer +from .constants import TEST_REGION class ServiceCommandsTests(ScenarioTest): @@ -114,12 +111,12 @@ def test_delete_service(self): self.cmd('az apic show -g {rg} -n {s}', expect_failure=True) @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) - @ApicServicePreparer(enable_system_assigned_identity=enable_system_assigned_identity) + @ApicServicePreparer() + @ApimServicePreparer() def test_import_from_apim(self): self.kwargs.update({ 'apim_name': self.create_random_name(prefix='cli', length=24) }) - self._prepare_apim() # Import from APIM self.cmd('az apic import-from-apim -g {rg} --service-name {s} --apim-name {apim_name} --apim-apis *') @@ -130,12 +127,12 @@ def test_import_from_apim(self): @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) - @ApicServicePreparer(enable_system_assigned_identity=enable_system_assigned_identity) + @ApicServicePreparer() + @ApimServicePreparer() def test_import_from_apim_for_one_api(self): self.kwargs.update({ 'apim_name': self.create_random_name(prefix='cli', length=24) }) - self._prepare_apim() # Import from APIM self.cmd('az apic import-from-apim -g {rg} --service-name {s} --apim-name {apim_name} --apim-apis echo') @@ -149,12 +146,12 @@ def test_import_from_apim_for_one_api(self): ]) @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) - @ApicServicePreparer(enable_system_assigned_identity=enable_system_assigned_identity) + @ApicServicePreparer() + @ApimServicePreparer() def test_import_from_apim_for_multiple_apis(self): self.kwargs.update({ 'apim_name': self.create_random_name(prefix='cli', length=24) }) - self._prepare_apim() # Import from APIM self.cmd('az apic import-from-apim -g {rg} --service-name {s} --apim-name {apim_name} --apim-apis [echo,foo]') @@ -198,21 +195,21 @@ def test_examples_delete_service(self): self.cmd('az apic show -g {rg} -n {s}', expect_failure=True) @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) - @ApicServicePreparer(enable_system_assigned_identity=enable_system_assigned_identity) + @ApicServicePreparer() + @ApimServicePreparer() def test_examples_import_all_apis_from_apim(self): self.kwargs.update({ 'apim_name': self.create_random_name(prefix='cli', length=24) }) - self._prepare_apim() self.cmd('az apic import-from-apim -g {rg} --service-name {s} --apim-name {apim_name} --apim-apis *') @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) - @ApicServicePreparer(enable_system_assigned_identity=enable_system_assigned_identity) + @ApicServicePreparer() + @ApimServicePreparer() def test_examples_import_selected_apis_from_apim(self): self.kwargs.update({ 'apim_name': self.create_random_name(prefix='cli', length=24) }) - self._prepare_apim() self.cmd('az apic import-from-apim -g {rg} --service-name {s} --apim-name {apim_name} --apim-apis [echo,foo]') @ResourceGroupPreparer(name_prefix="clirg", location=TEST_REGION, random_name_length=32) @@ -235,32 +232,3 @@ def test_examples_show_service_details(self): @ApicServicePreparer() def test_examples_update_service_details(self): self.cmd('az apic update -g {rg} -n {s}') - - def _prepare_apim(self): - if self.is_live: - # Only setup APIM in live mode - # Get system assigned identity id for API Center - apic_service = self.cmd('az apic show -g {rg} -n {s}').get_output_in_json() - self.kwargs.update({ - 'identity_id': apic_service['identity']['principalId'] - }) if enable_system_assigned_identity else None - # Create APIM service - apim_service = self.cmd('az apim create -g {rg} --name {apim_name} --publisher-name test --publisher-email test@example.com --sku-name Consumption').get_output_in_json() - # Add echo api - self.cmd('az apim api create -g {rg} --service-name {apim_name} --api-id echo --display-name "Echo API" --path "/echo"') - self.cmd('az apim api operation create -g {rg} --service-name {apim_name} --api-id echo --url-template "/echo" --method "GET" --display-name "GetOperation"') - # Add foo api - self.cmd('az apim api create -g {rg} --service-name {apim_name} --api-id foo --display-name "Foo API" --path "/foo"') - self.cmd('az apim api operation create -g {rg} --service-name {apim_name} --api-id foo --url-template "/foo" --method "GET" --display-name "GetOperation"') - apim_id = apim_service['id'] - self.kwargs.update({ - 'apim_id': apim_id, - 'usi_id': USERASSIGNED_IDENTITY - }) - - if enable_system_assigned_identity: - # Grant system assigned identity of API Center access to APIM - self.cmd('az role assignment create --role "API Management Service Reader Role" --assignee-object-id {identity_id} --assignee-principal-type ServicePrincipal --scope {apim_id}') - else: - # add user-assigned identity to api center service: - self.cmd('az apic update --name {s} -g {rg} --identity {{type:UserAssigned,user-assigned-identities:{usi_id}}}') \ No newline at end of file diff --git a/src/apic-extension/azext_apic_extension/tests/latest/utils.py b/src/apic-extension/azext_apic_extension/tests/latest/utils.py index b1106da4a1f..a785563f138 100644 --- a/src/apic-extension/azext_apic_extension/tests/latest/utils.py +++ b/src/apic-extension/azext_apic_extension/tests/latest/utils.py @@ -4,16 +4,17 @@ # -------------------------------------------------------------------------------------------- from azure.cli.testsdk.preparers import NoTrafficRecordingPreparer, SingleValueReplacer, get_dummy_cli, CliTestError, ResourceGroupPreparer +from .constants import USERASSIGNED_IDENTITY class ApicServicePreparer(NoTrafficRecordingPreparer, SingleValueReplacer): def __init__(self, name_prefix='clitest', length=24, - parameter_name='service_name', resource_group_parameter_name='resource_group', key='s', - enable_system_assigned_identity=False): + parameter_name='service_name', resource_group_parameter_name='resource_group', key='s', + user_assigned_identity = None): super(ApicServicePreparer, self).__init__(name_prefix, length) self.cli_ctx = get_dummy_cli() self.resource_group_parameter_name = resource_group_parameter_name self.parameter_name = parameter_name - self.enable_system_assigned_identity = enable_system_assigned_identity + self.user_assigned_identity = user_assigned_identity self.key = key def create_resource(self, name, **kwargs): @@ -21,10 +22,13 @@ def create_resource(self, name, **kwargs): template = 'az apic create --name {} -g {}' - if self.enable_system_assigned_identity: + if self.user_assigned_identity is None: template += ' --identity \'{{type:SystemAssigned}}\'' + cmd = template.format(name, group) + else: + template += ' --identity \'{{type:UserAssigned,user-assigned-identities:\'{{{}}}\'}}\'' + cmd = template.format(name, group, self.user_assigned_identity) - cmd=template.format(name, group) print(cmd) self.live_only_execute(self.cli_ctx, cmd) @@ -380,3 +384,79 @@ def _get_apic_environment(self, **kwargs): template = 'To create an API Center Deployment an API Center Environment is required. Please add ' \ 'decorator @{} in front of this preparer.' raise CliTestError(template.format(ApicEnvironmentPreparer.__name__)) + +class ApimServicePreparer(NoTrafficRecordingPreparer, SingleValueReplacer): + def __init__(self, name_prefix='clitest', length=24, + parameter_name='apim_name', resource_group_parameter_name='resource_group', + apic_service_name = 'service_name', + key='apim'): + super(ApimServicePreparer, self).__init__(name_prefix, length) + self.cli_ctx = get_dummy_cli() + self.resource_group_parameter_name = resource_group_parameter_name + self.apic_service_name = apic_service_name + self.parameter_name = parameter_name + self.use_system_assigned_identity = False if USERASSIGNED_IDENTITY else True + self.key = key + + def create_resource(self, name, **kwargs): + self.test_class_instance.kwargs['use_system_assigned_identity'] = self.use_system_assigned_identity + group = self._get_resource_group(**kwargs) + service_name = self._get_apic_service(**kwargs) + + # Only setup APIM in live mode + if self.test_class_instance.is_live: + # Get system assigned identity id for API Center + apic_service = self.test_class_instance.cmd('az apic show -g {} -n {}'.format(group, service_name)).get_output_in_json() + if self.use_system_assigned_identity: + self.test_class_instance.kwargs.update({ + 'identity_id': apic_service['identity']['principalId'] + }) + + # Create APIM service + apim_service = self.test_class_instance.cmd('az apim create -g {} --name {} --publisher-name test --publisher-email test@example.com --sku-name Consumption'.format(group, name)).get_output_in_json() + apim_id = apim_service['id'] + self.test_class_instance.kwargs[self.parameter_name] = name + self.test_class_instance.kwargs.update({ + 'apim_id': apim_id, + 'usi_id': USERASSIGNED_IDENTITY, + 'apic_service_name': service_name, + 'group': group + }) + + # Add echo api + self.test_class_instance.cmd('az apim api create -g {} --service-name {} --api-id echo --display-name "Echo API" --path "/echo"'.format(group, name)) + self.test_class_instance.cmd('az apim api operation create -g {} --service-name {} --api-id echo --url-template "/echo" --method "GET" --display-name "GetOperation"'.format(group, name)) + # Add foo api + self.test_class_instance.cmd('az apim api create -g {} --service-name {} --api-id foo --display-name "Foo API" --path "/foo"'.format(group, name)) + self.test_class_instance.cmd('az apim api operation create -g {} --service-name {} --api-id foo --url-template "/foo" --method "GET" --display-name "GetOperation"'.format(group, name)) + + if self.use_system_assigned_identity: + # Grant system assigned identity of API Center access to APIM + self.test_class_instance.cmd('az role assignment create --role "API Management Service Reader Role" --assignee-object-id {} --assignee-principal-type ServicePrincipal --scope {}'.format(self.test_class_instance.kwargs['identity_id'], apim_id)) + else: + # Attach user assigned identity with access to APIM to API Center + # In APICServicePreparer, we already attached the user assigned identity provided by user to API Center. Please check it. + self.test_class_instance.cmd('az apic update --name {apic_service_name} -g {group} --identity {{type:UserAssigned,user-assigned-identities:{{{usi_id}}}}}') + + self.test_class_instance.kwargs[self.parameter_name] = name + return {self.parameter_name: name} + + def remove_resource(self, name, **kwargs): + # ResourceGroupPreparer will delete everything + pass + + def _get_resource_group(self, **kwargs): + try: + return kwargs.get(self.resource_group_parameter_name) + except KeyError: + template = 'To create an API Management service a resource group is required. Please add ' \ + 'decorator @{} in front of this preparer.' + raise CliTestError(template.format(ResourceGroupPreparer.__name__)) + + def _get_apic_service(self, **kwargs): + try: + return kwargs.get(self.apic_service_name) + except KeyError: + template = 'To create an API Center service is required. Please add ' \ + 'decorator @{} in front of this preparer.' + raise CliTestError(template.format(ApicServicePreparer.__name__))