diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b3a508c0d5e..7836131323c 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,8 +20,6 @@ jobs: - name: Setup development environment run: | - pip install azure-cli==2.63.0 # Specify the version of azure-cli - pip install azure-core==1.28.0 # Specify the version of azsdk-python-core python -m venv .venv source .venv/bin/activate python -m pip install -U pip 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_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 index 39776986ebc..e17bff39d0b 100644 --- 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 @@ -9,7 +9,7 @@ from azure.cli.testsdk.checkers import JMESPathCheck from azure.cli.testsdk.exceptions import JMESPathCheckAssertionError from .utils import ApicServicePreparer, ApimServicePreparer -from .constants import TEST_REGION, USERASSIGNED_IDENTITY +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): @@ -47,7 +47,7 @@ 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) + 'integration_name': self.create_random_name(prefix='cli', length=8) }) if self.kwargs['use_system_assigned_identity'] or not self.is_live: @@ -63,8 +63,23 @@ def test_integration_create_apim(self): ]) @ResourceGroupPreparer(name_prefix="clirg", location="centraluseuap", random_name_length=32) - @ApicServicePreparer() - @ApimServicePreparer() + @ApicServicePreparer(user_assigned_identity=USERASSIGNED_IDENTITY) def test_integration_create_aws(self): - # TODO: add codes for AWS integration test - pass + 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/utils.py b/src/apic-extension/azext_apic_extension/tests/latest/utils.py index e146bbeb820..5856ab3f727 100644 --- a/src/apic-extension/azext_apic_extension/tests/latest/utils.py +++ b/src/apic-extension/azext_apic_extension/tests/latest/utils.py @@ -8,12 +8,13 @@ class ApicServicePreparer(NoTrafficRecordingPreparer, SingleValueReplacer): def __init__(self, name_prefix='clitest', length=24, - parameter_name='service_name', resource_group_parameter_name='resource_group', key='s'): + 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.use_system_assigned_identity = False if USERASSIGNED_IDENTITY else True + self.user_assigned_identity = user_assigned_identity self.key = key def create_resource(self, name, **kwargs): @@ -21,13 +22,20 @@ def create_resource(self, name, **kwargs): template = 'az apic create --name {} -g {}' - if self.use_system_assigned_identity: + if self.user_assigned_identity is None: template += ' --identity \'{{type:SystemAssigned}}\'' cmd=template.format(name, group) print(cmd) self.live_only_execute(self.cli_ctx, cmd) + # Attach user assigned identity to the API Center service + if self.user_assigned_identity: + template = 'az apic update --name {} -g {} --identity \'{{type:UserAssigned,user-assigned-identities:\'{{{}}}\'}}\'' + cmd = template.format(name, group, self.user_assigned_identity) + print(cmd) + self.live_only_execute(self.cli_ctx, cmd) + self.test_class_instance.kwargs[self.key] = name return {self.parameter_name: name} @@ -430,7 +438,8 @@ def create_resource(self, name, **kwargs): # 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 + # 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