ApplicationAutoscaling: support for all the current various forms of resource_id (#3305)
* Change to test_s3 method test_presigned_url_restrict_parameters to tolerate change in exception messages, spurred by boto3 1.14.59 release. * ApplicationAutoscaling: support for all the current various forms of resource_id. * Factored logic for extracting application autoscaling resource_type from resource_id to separate function, per PR3304 comment. Co-authored-by: Joseph Weitekamp <jweite@amazon.com>
This commit is contained in:
parent
7ce1e87477
commit
da4de072a9
@ -135,7 +135,7 @@ def _target_params_are_valid(namespace, r_id, dimension):
|
||||
try:
|
||||
valid_dimensions = [d.value for d in ScalableDimensionValueSet]
|
||||
d_namespace, d_resource_type, scaling_property = dimension.split(":")
|
||||
resource_type, cluster, service = r_id.split("/")
|
||||
resource_type = _get_resource_type_from_resource_id(r_id)
|
||||
if (
|
||||
dimension not in valid_dimensions
|
||||
or d_namespace != namespace
|
||||
@ -151,6 +151,33 @@ def _target_params_are_valid(namespace, r_id, dimension):
|
||||
return is_valid
|
||||
|
||||
|
||||
def _get_resource_type_from_resource_id(resource_id):
|
||||
# AWS Application Autoscaling resource_ids are multi-component (path-like) identifiers that vary in format,
|
||||
# depending on the type of resource it identifies. resource_type is one of its components.
|
||||
# resource_id format variations are described in
|
||||
# https://docs.aws.amazon.com/autoscaling/application/APIReference/API_RegisterScalableTarget.html
|
||||
# In a nutshell:
|
||||
# - Most use slash separators, but some use colon separators.
|
||||
# - The resource type is usually the first component of the resource_id...
|
||||
# - ...except for sagemaker endpoints, dynamodb GSIs and keyspaces tables, where it's the third.
|
||||
# - Comprehend uses an arn, with the resource type being the last element.
|
||||
|
||||
if resource_id.startswith("arn:aws:comprehend"):
|
||||
resource_id = resource_id.split(":")[-1]
|
||||
resource_split = (
|
||||
resource_id.split("/") if "/" in resource_id else resource_id.split(":")
|
||||
)
|
||||
if (
|
||||
resource_split[0] == "endpoint"
|
||||
or (resource_split[0] == "table" and len(resource_split) > 2)
|
||||
or (resource_split[0] == "keyspace")
|
||||
):
|
||||
resource_type = resource_split[2]
|
||||
else:
|
||||
resource_type = resource_split[0]
|
||||
return resource_type
|
||||
|
||||
|
||||
class FakeScalableTarget(BaseModel):
|
||||
def __init__(
|
||||
self, backend, service_namespace, resource_id, scalable_dimension, **kwargs
|
||||
|
@ -187,3 +187,76 @@ def register_scalable_target(client, **kwargs):
|
||||
RoleARN=kwargs.get("RoleARN", DEFAULT_ROLE_ARN),
|
||||
SuspendedState=kwargs.get("SuspendedState", DEFAULT_SUSPENDED_STATE),
|
||||
)
|
||||
|
||||
|
||||
@mock_ecs
|
||||
@mock_applicationautoscaling
|
||||
def test_register_scalable_target_resource_id_variations():
|
||||
|
||||
# Required to register an ECS target in moto
|
||||
ecs = boto3.client("ecs", region_name=DEFAULT_REGION)
|
||||
_create_ecs_defaults(ecs)
|
||||
|
||||
# See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationautoscaling-scalabletarget.html
|
||||
resource_id_variations = [
|
||||
(
|
||||
DEFAULT_SERVICE_NAMESPACE,
|
||||
DEFAULT_RESOURCE_ID,
|
||||
DEFAULT_SCALABLE_DIMENSION,
|
||||
), # ECS
|
||||
(
|
||||
"ec2",
|
||||
"spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE",
|
||||
"ec2:spot-fleet-request:TargetCapacity",
|
||||
),
|
||||
(
|
||||
"elasticmapreduce",
|
||||
"instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0",
|
||||
"elasticmapreduce:instancegroup:InstanceCount",
|
||||
),
|
||||
("appstream", "fleet/sample-fleet", "appstream:fleet:DesiredCapacity"),
|
||||
("dynamodb", "table/my-table", "dynamodb:table:ReadCapacityUnits"),
|
||||
(
|
||||
"dynamodb",
|
||||
"table/my-table/index/my-table-index",
|
||||
"dynamodb:index:ReadCapacityUnits",
|
||||
),
|
||||
("rds", "cluster:my-db-cluster", "rds:cluster:ReadReplicaCount"),
|
||||
(
|
||||
"sagemaker",
|
||||
"endpoint/MyEndPoint/variant/MyVariant",
|
||||
"sagemaker:variant:DesiredInstanceCount",
|
||||
),
|
||||
(
|
||||
"comprehend",
|
||||
"arn:aws:comprehend:us-west-2:123456789012:document-classifier-endpoint/EXAMPLE",
|
||||
"comprehend:document-classifier-endpoint:DesiredInferenceUnits",
|
||||
),
|
||||
(
|
||||
"lambda",
|
||||
"function:my-function:prod",
|
||||
"lambda:function:ProvisionedConcurrency",
|
||||
),
|
||||
(
|
||||
"cassandra",
|
||||
"keyspace/mykeyspace/table/mytable",
|
||||
"cassandra:table:ReadCapacityUnits",
|
||||
),
|
||||
]
|
||||
|
||||
client = boto3.client("application-autoscaling", region_name=DEFAULT_REGION)
|
||||
for namespace, resource_id, scalable_dimension in resource_id_variations:
|
||||
client.register_scalable_target(
|
||||
ServiceNamespace=namespace,
|
||||
ResourceId=resource_id,
|
||||
ScalableDimension=scalable_dimension,
|
||||
)
|
||||
response = client.describe_scalable_targets(ServiceNamespace=namespace)
|
||||
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||
num_targets = 2 if namespace == "dynamodb" and "index" in resource_id else 1
|
||||
len(response["ScalableTargets"]).should.equal(num_targets)
|
||||
t = response["ScalableTargets"][-1]
|
||||
t.should.have.key("ServiceNamespace").which.should.equal(namespace)
|
||||
t.should.have.key("ResourceId").which.should.equal(resource_id)
|
||||
t.should.have.key("ScalableDimension").which.should.equal(scalable_dimension)
|
||||
t.should.have.key("CreationTime").which.should.be.a("datetime.datetime")
|
||||
|
Loading…
Reference in New Issue
Block a user