diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py index fad7ca7e1485..43b71cfc62bd 100644 --- a/moto/apigateway/models.py +++ b/moto/apigateway/models.py @@ -1658,7 +1658,7 @@ def create_rest_api( ) -> RestAPI: api_id = ApigwRestApiIdentifier( self.account_id, self.region_name, name - ).generate() + ).generate(tags=tags) rest_api = RestAPI( api_id, self.account_id, diff --git a/moto/secretsmanager/models.py b/moto/secretsmanager/models.py index 8d3d1d5a2e81..b2f185fb0bb0 100644 --- a/moto/secretsmanager/models.py +++ b/moto/secretsmanager/models.py @@ -100,7 +100,7 @@ def __init__( self.name = secret_id self.arn = SecretsManagerSecretIdentifier( account_id, region_name, secret_id - ).generate() + ).generate(tags=tags) self.account_id = account_id self.region = region_name self.secret_string = secret_string diff --git a/moto/utilities/id_generator.py b/moto/utilities/id_generator.py index c5f0a2c938f5..a26464a43cc9 100644 --- a/moto/utilities/id_generator.py +++ b/moto/utilities/id_generator.py @@ -8,7 +8,7 @@ log = logging.getLogger(__name__) ExistingIds = Union[List[str], None] -Tags = Union[Dict[str, str], None] +Tags = Union[Dict[str, str], List[Dict[str, str]], None] # Custom resource tag to override the generated resource ID. TAG_KEY_CUSTOM_ID = "_custom_id_" @@ -71,7 +71,8 @@ def __init__(self) -> None: def get_custom_id( self, resource_identifier: ResourceIdentifier ) -> Union[str, None]: - # retrieves a custom_id for a resource. Returns None + # retrieves a custom_id for a resource. Returns None if no id were registered + # that matches the `resource_identifier` return self._custom_ids.get(resource_identifier.unique_identifier) def set_custom_id( @@ -95,10 +96,21 @@ def add_id_source( @staticmethod def get_id_from_tags(id_source_context: IdSourceContext) -> Union[str, None]: - if tags := id_source_context.get("tags"): + if not (tags := id_source_context.get("tags")): + return None + + if isinstance(tags, dict): return tags.get(TAG_KEY_CUSTOM_ID) - return None + if isinstance(tags, list): + return next( + ( + tag.get("Value") + for tag in tags + if tag.get("Key") == TAG_KEY_CUSTOM_ID + ), + None, + ) def get_custom_id_from_context( self, id_source_context: IdSourceContext diff --git a/tests/test_apigateway/test_apigateway_custom_ids.py b/tests/test_apigateway/test_apigateway_custom_ids.py index 1d2debbbafff..3bfdc544c566 100644 --- a/tests/test_apigateway/test_apigateway_custom_ids.py +++ b/tests/test_apigateway/test_apigateway_custom_ids.py @@ -11,6 +11,8 @@ ApigwRestApiIdentifier, ApigwUsagePlanIdentifier, ) +from moto.utilities.id_generator import TAG_KEY_CUSTOM_ID +from tests import DEFAULT_ACCOUNT_ID API_ID = "ApiId" API_KEY_ID = "ApiKeyId" @@ -27,7 +29,7 @@ @pytest.mark.skipif( not settings.TEST_DECORATOR_MODE, reason="Can't access the id manager in proxy mode" ) -def test_custom_id_rest_api(set_custom_id, account_id): +def test_custom_id_rest_api(set_custom_id): region_name = "us-west-2" rest_api_name = "my-api" model_name = "modelName" @@ -37,33 +39,40 @@ def test_custom_id_rest_api(set_custom_id, account_id): client = boto3.client("apigateway", region_name=region_name) set_custom_id( - ApigwRestApiIdentifier(account_id, region_name, rest_api_name), API_ID + ApigwRestApiIdentifier(DEFAULT_ACCOUNT_ID, region_name, rest_api_name), API_ID ) set_custom_id( - ApigwResourceIdentifier(account_id, region_name, path_name="/"), + ApigwResourceIdentifier(DEFAULT_ACCOUNT_ID, region_name, path_name="/"), ROOT_RESOURCE_ID, ) set_custom_id( ApigwResourceIdentifier( - account_id, region_name, parent_id=ROOT_RESOURCE_ID, path_name="pet" + DEFAULT_ACCOUNT_ID, region_name, parent_id=ROOT_RESOURCE_ID, path_name="pet" ), PET_1_RESOURCE_ID, ) set_custom_id( ApigwResourceIdentifier( - account_id, region_name, parent_id=PET_1_RESOURCE_ID, path_name="pet" + DEFAULT_ACCOUNT_ID, + region_name, + parent_id=PET_1_RESOURCE_ID, + path_name="pet", ), PET_2_RESOURCE_ID, ) - set_custom_id(ApigwModelIdentifier(account_id, region_name, model_name), MODEL_ID) + set_custom_id( + ApigwModelIdentifier(DEFAULT_ACCOUNT_ID, region_name, model_name), MODEL_ID + ) set_custom_id( ApigwRequestValidatorIdentifier( - account_id, region_name, request_validator_name + DEFAULT_ACCOUNT_ID, region_name, request_validator_name ), REQUEST_VALIDATOR_ID, ) set_custom_id( - ApigwDeploymentIdentifier(account_id, region_name, stage_name=stage_name), + ApigwDeploymentIdentifier( + DEFAULT_ACCOUNT_ID, region_name, stage_name=stage_name + ), DEPLOYMENT_ID, ) @@ -113,7 +122,7 @@ def test_custom_id_rest_api(set_custom_id, account_id): @pytest.mark.skipif( not settings.TEST_DECORATOR_MODE, reason="Can't access the id manager in proxy mode" ) -def test_custom_id_api_key(account_id, set_custom_id): +def test_custom_id_api_key(set_custom_id): region_name = "us-west-2" api_key_value = "01234567890123456789" usage_plan_name = "usage-plan" @@ -121,10 +130,11 @@ def test_custom_id_api_key(account_id, set_custom_id): client = boto3.client("apigateway", region_name=region_name) set_custom_id( - ApigwApiKeyIdentifier(account_id, region_name, value=api_key_value), API_KEY_ID + ApigwApiKeyIdentifier(DEFAULT_ACCOUNT_ID, region_name, value=api_key_value), + API_KEY_ID, ) set_custom_id( - ApigwUsagePlanIdentifier(account_id, region_name, usage_plan_name), + ApigwUsagePlanIdentifier(DEFAULT_ACCOUNT_ID, region_name, usage_plan_name), USAGE_PLAN_ID, ) @@ -138,3 +148,15 @@ def test_custom_id_api_key(account_id, set_custom_id): assert api_key["id"] == API_KEY_ID assert usage_plan["id"] == USAGE_PLAN_ID + + +@mock_aws +def test_create_rest_api_with_custom_id_tag(): + rest_api_name = "rest_api" + api_id = "testTagId" + client = boto3.client("apigateway", region_name="us-west-2") + rest_api = client.create_rest_api( + name=rest_api_name, tags={TAG_KEY_CUSTOM_ID: api_id} + ) + + assert rest_api["id"] == api_id diff --git a/tests/test_secretsmanager/test_secretsmanager.py b/tests/test_secretsmanager/test_secretsmanager.py index 734fcf38420c..b98349b4cea9 100644 --- a/tests/test_secretsmanager/test_secretsmanager.py +++ b/tests/test_secretsmanager/test_secretsmanager.py @@ -14,7 +14,9 @@ from moto import mock_aws, settings from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID from moto.secretsmanager.utils import SecretsManagerSecretIdentifier +from moto.utilities.id_generator import TAG_KEY_CUSTOM_ID +from .. import DEFAULT_ACCOUNT_ID from . import secretsmanager_aws_verified DEFAULT_SECRET_NAME = "test-secret7" @@ -1968,7 +1970,7 @@ def test_update_secret_version_stage_dont_specify_current_stage(secret_arn=None) @pytest.mark.skipif( not settings.TEST_DECORATOR_MODE, reason="Can't access the id manager in proxy mode" ) -def test_create_secret_custom_id(account_id, set_custom_id): +def test_create_secret_custom_id(set_custom_id): secret_suffix = "randomSuffix" secret_name = "secret-name" region_name = "us-east-1" @@ -1976,9 +1978,25 @@ def test_create_secret_custom_id(account_id, set_custom_id): client = boto3.client("secretsmanager", region_name=region_name) set_custom_id( - SecretsManagerSecretIdentifier(account_id, region_name, secret_name), + SecretsManagerSecretIdentifier(DEFAULT_ACCOUNT_ID, region_name, secret_name), secret_suffix, ) secret = client.create_secret(Name=secret_name, SecretString="my secret") assert secret["ARN"].split(":")[-1] == f"{secret_name}-{secret_suffix}" + + +@mock_aws +def test_create_secret_with_tag_custom_id(set_custom_id): + secret_suffix = "randomSuffix" + secret_name = "secret-name" + + client = boto3.client("secretsmanager") + + secret = client.create_secret( + Name=secret_name, + SecretString="my secret", + Tags=[{"Key": TAG_KEY_CUSTOM_ID, "Value": secret_suffix}], + ) + + assert secret["ARN"].split(":")[-1] == f"{secret_name}-{secret_suffix}" diff --git a/tests/test_utilities/test_id_generator.py b/tests/test_utilities/test_id_generator.py index 7ee85fd32f3f..45ff2a0439f9 100644 --- a/tests/test_utilities/test_id_generator.py +++ b/tests/test_utilities/test_id_generator.py @@ -12,7 +12,7 @@ RESOURCE_NAME = "my-resource" CUSTOM_ID = "custom" -GENERATED_ID = "generated" +GENERIC_ID = "generated" TAG_ID = "fromTag" SERVICE = "test-service" RESOURCE = "test-resource" @@ -24,7 +24,7 @@ def generate_test_id( existing_ids: ExistingIds = None, tags: Tags = None, ): - return GENERATED_ID + return GENERIC_ID class TestResourceIdentifier(ResourceIdentifier): @@ -39,7 +39,7 @@ def generate(self, existing_ids: ExistingIds = None, tags: Tags = None) -> str: def test_generate_with_no_resource_identifier(): generated_id = generate_test_id(None) - assert generated_id == GENERATED_ID + assert generated_id == GENERIC_ID def test_generate_with_matching_resource_identifier(set_custom_id): @@ -58,7 +58,7 @@ def test_generate_with_non_matching_resource_identifier(set_custom_id): set_custom_id(resource_identifier, CUSTOM_ID) generated_id = generate_test_id(resource_identifier=resource_identifier_2) - assert generated_id == GENERATED_ID + assert generated_id == GENERIC_ID def test_generate_with_custom_id_tag(): @@ -87,7 +87,7 @@ def test_generate_with_existing_id(set_custom_id): generated_id = generate_test_id( resource_identifier=resource_identifier, existing_ids=[CUSTOM_ID] ) - assert generated_id == GENERATED_ID + assert generated_id == GENERIC_ID def test_generate_with_tags_and_existing_id(set_custom_id): @@ -98,7 +98,7 @@ def test_generate_with_tags_and_existing_id(set_custom_id): existing_ids=[TAG_ID], tags={TAG_KEY_CUSTOM_ID: TAG_ID}, ) - assert generated_id == GENERATED_ID + assert generated_id == GENERIC_ID def test_generate_with_tags_fallback(set_custom_id):