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:
|
try:
|
||||||
valid_dimensions = [d.value for d in ScalableDimensionValueSet]
|
valid_dimensions = [d.value for d in ScalableDimensionValueSet]
|
||||||
d_namespace, d_resource_type, scaling_property = dimension.split(":")
|
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 (
|
if (
|
||||||
dimension not in valid_dimensions
|
dimension not in valid_dimensions
|
||||||
or d_namespace != namespace
|
or d_namespace != namespace
|
||||||
@ -151,6 +151,33 @@ def _target_params_are_valid(namespace, r_id, dimension):
|
|||||||
return is_valid
|
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):
|
class FakeScalableTarget(BaseModel):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, backend, service_namespace, resource_id, scalable_dimension, **kwargs
|
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),
|
RoleARN=kwargs.get("RoleARN", DEFAULT_ROLE_ARN),
|
||||||
SuspendedState=kwargs.get("SuspendedState", DEFAULT_SUSPENDED_STATE),
|
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