Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom id tag support #8230

Merged
merged 4 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion moto/apigateway/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion moto/secretsmanager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 16 additions & 4 deletions moto/utilities/id_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_"
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down
44 changes: 33 additions & 11 deletions tests/test_apigateway/test_apigateway_custom_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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,
)

Expand Down Expand Up @@ -113,18 +122,19 @@ 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"

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,
)

Expand All @@ -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
22 changes: 20 additions & 2 deletions tests/test_secretsmanager/test_secretsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1968,17 +1970,33 @@ 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"

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}"
12 changes: 6 additions & 6 deletions tests/test_utilities/test_id_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,7 +24,7 @@ def generate_test_id(
existing_ids: ExistingIds = None,
tags: Tags = None,
):
return GENERATED_ID
return GENERIC_ID


class TestResourceIdentifier(ResourceIdentifier):
Expand All @@ -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):
Expand All @@ -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():
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down
Loading