From b9a42816bdd327013854fd842fb8530dbb0bc5eb Mon Sep 17 00:00:00 2001
From: psheets <4058236+psheets@users.noreply.github.com>
Date: Wed, 23 Jun 2021 11:57:09 -0400
Subject: [PATCH] Fixed validation on custom-resource in applicationautoscaling
(#4026)
* Added ResourceTypeExceptions
* Added test for custom-resource
Co-authored-by: Phil Sheets
---
moto/applicationautoscaling/models.py | 21 +++++++++++++------
moto/applicationautoscaling/responses.py | 4 ++--
moto/core/models.py | 2 +-
moto/ec2/models.py | 2 +-
moto/ecs/models.py | 2 +-
moto/elb/models.py | 2 +-
moto/elbv2/models.py | 2 +-
moto/packages/httpretty/core.py | 2 +-
moto/route53/models.py | 2 +-
.../test_applicationautoscaling.py | 5 +++++
10 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/moto/applicationautoscaling/models.py b/moto/applicationautoscaling/models.py
index 13c761e83..1d9fb5be2 100644
--- a/moto/applicationautoscaling/models.py
+++ b/moto/applicationautoscaling/models.py
@@ -8,6 +8,11 @@ import time
import uuid
+@unique
+class ResourceTypeExceptionValueSet(Enum):
+ RESOURCE_TYPE = "ResourceType"
+
+
@unique
class ServiceNamespaceValueSet(Enum):
APPSTREAM = "appstream"
@@ -74,7 +79,7 @@ class ApplicationAutoscalingBackend(BaseBackend):
def describe_scalable_targets(
self, namespace, r_ids=None, dimension=None,
):
- """ Describe scalable targets. """
+ """Describe scalable targets."""
if r_ids is None:
r_ids = []
targets = self._flatten_scalable_targets(namespace)
@@ -85,7 +90,7 @@ class ApplicationAutoscalingBackend(BaseBackend):
return targets
def _flatten_scalable_targets(self, namespace):
- """ Flatten scalable targets for a given service namespace down to a list. """
+ """Flatten scalable targets for a given service namespace down to a list."""
targets = []
for dimension in self.targets.keys():
for resource_id in self.targets[dimension].keys():
@@ -94,7 +99,7 @@ class ApplicationAutoscalingBackend(BaseBackend):
return targets
def register_scalable_target(self, namespace, r_id, dimension, **kwargs):
- """ Registers or updates a scalable target. """
+ """Registers or updates a scalable target."""
_ = _target_params_are_valid(namespace, r_id, dimension)
if namespace == ServiceNamespaceValueSet.ECS.value:
_ = self._ecs_service_exists_for_target(r_id)
@@ -127,7 +132,7 @@ class ApplicationAutoscalingBackend(BaseBackend):
return target
def deregister_scalable_target(self, namespace, r_id, dimension):
- """ Registers or updates a scalable target. """
+ """Registers or updates a scalable target."""
if self._scalable_target_exists(r_id, dimension):
del self.targets[dimension][r_id]
else:
@@ -222,7 +227,7 @@ class ApplicationAutoscalingBackend(BaseBackend):
def _target_params_are_valid(namespace, r_id, dimension):
- """ Check whether namespace, resource_id and dimension are valid and consistent with each other. """
+ """Check whether namespace, resource_id and dimension are valid and consistent with each other."""
is_valid = True
valid_namespaces = [n.value for n in ServiceNamespaceValueSet]
if namespace not in valid_namespaces:
@@ -230,8 +235,12 @@ def _target_params_are_valid(namespace, r_id, dimension):
if dimension is not None:
try:
valid_dimensions = [d.value for d in ScalableDimensionValueSet]
+ resource_type_exceptions = [r.value for r in ResourceTypeExceptionValueSet]
d_namespace, d_resource_type, scaling_property = dimension.split(":")
- resource_type = _get_resource_type_from_resource_id(r_id)
+ if d_resource_type not in resource_type_exceptions:
+ resource_type = _get_resource_type_from_resource_id(r_id)
+ else:
+ resource_type = d_resource_type
if (
dimension not in valid_dimensions
or d_namespace != namespace
diff --git a/moto/applicationautoscaling/responses.py b/moto/applicationautoscaling/responses.py
index ad63af948..c994fe12f 100644
--- a/moto/applicationautoscaling/responses.py
+++ b/moto/applicationautoscaling/responses.py
@@ -33,7 +33,7 @@ class ApplicationAutoScalingResponse(BaseResponse):
return json.dumps({"ScalableTargets": targets, "NextToken": next_token})
def register_scalable_target(self):
- """ Registers or updates a scalable target. """
+ """Registers or updates a scalable target."""
self._validate_params()
self.applicationautoscaling_backend.register_scalable_target(
self._get_param("ServiceNamespace"),
@@ -47,7 +47,7 @@ class ApplicationAutoScalingResponse(BaseResponse):
return json.dumps({})
def deregister_scalable_target(self):
- """ Deregisters a scalable target. """
+ """Deregisters a scalable target."""
self._validate_params()
self.applicationautoscaling_backend.deregister_scalable_target(
self._get_param("ServiceNamespace"),
diff --git a/moto/core/models.py b/moto/core/models.py
index f8ec9ee37..05f0c37d2 100644
--- a/moto/core/models.py
+++ b/moto/core/models.py
@@ -547,7 +547,7 @@ class Model(type):
@staticmethod
def prop(model_name):
- """ decorator to mark a class method as returning model values """
+ """decorator to mark a class method as returning model values"""
def dec(f):
f.__returns_model__ = model_name
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
index 725a903f9..fe47079b4 100644
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -2105,7 +2105,7 @@ class SecurityGroup(TaggedEC2Resource, CloudFormationModel):
security_group.delete(region_name)
def delete(self, region_name):
- """ Not exposed as part of the ELB API - used for CloudFormation. """
+ """Not exposed as part of the ELB API - used for CloudFormation."""
self.ec2_backend.delete_security_group(group_id=self.id)
@property
diff --git a/moto/ecs/models.py b/moto/ecs/models.py
index 863275ab4..b86b7b52c 100644
--- a/moto/ecs/models.py
+++ b/moto/ecs/models.py
@@ -1646,7 +1646,7 @@ class EC2ContainerServiceBackend(BaseBackend):
return task_set_obj
def update_service_primary_task_set(self, cluster, service, primary_task_set):
- """ Updates task sets be PRIMARY or ACTIVE for given cluster:service task sets """
+ """Updates task sets be PRIMARY or ACTIVE for given cluster:service task sets"""
cluster_name = cluster.split("/")[-1]
service_name = service.split("/")[-1]
task_set_obj = self.describe_task_sets(
diff --git a/moto/elb/models.py b/moto/elb/models.py
index 464ae8325..bb245a0fb 100644
--- a/moto/elb/models.py
+++ b/moto/elb/models.py
@@ -265,7 +265,7 @@ class FakeLoadBalancer(CloudFormationModel):
del self.tags[key]
def delete(self, region):
- """ Not exposed as part of the ELB API - used for CloudFormation. """
+ """Not exposed as part of the ELB API - used for CloudFormation."""
elb_backends[region].delete_load_balancer(self.name)
diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py
index ee258ca43..178dc72b4 100644
--- a/moto/elbv2/models.py
+++ b/moto/elbv2/models.py
@@ -480,7 +480,7 @@ class FakeLoadBalancer(CloudFormationModel):
self.state = "active"
def delete(self, region):
- """ Not exposed as part of the ELB API - used for CloudFormation. """
+ """Not exposed as part of the ELB API - used for CloudFormation."""
elbv2_backends[region].delete_load_balancer(self.arn)
@staticmethod
diff --git a/moto/packages/httpretty/core.py b/moto/packages/httpretty/core.py
index 2f48ad567..22fe21c81 100644
--- a/moto/packages/httpretty/core.py
+++ b/moto/packages/httpretty/core.py
@@ -212,7 +212,7 @@ class HTTPrettyRequest(BaseHTTPRequestHandler, BaseClass):
return result
def parse_request_body(self, body):
- """ Attempt to parse the post based on the content-type passed. Return the regular body if not """
+ """Attempt to parse the post based on the content-type passed. Return the regular body if not"""
PARSING_FUNCTIONS = {
"application/json": json.loads,
diff --git a/moto/route53/models.py b/moto/route53/models.py
index 8cb4520c1..be5109f74 100644
--- a/moto/route53/models.py
+++ b/moto/route53/models.py
@@ -208,7 +208,7 @@ class RecordSet(CloudFormationModel):
return template.render(record_set=self)
def delete(self, *args, **kwargs):
- """ Not exposed as part of the Route 53 API - used for CloudFormation. args are ignored """
+ """Not exposed as part of the Route 53 API - used for CloudFormation. args are ignored"""
hosted_zone = route53_backend.get_hosted_zone_by_name(self.hosted_zone_name)
if not hosted_zone:
hosted_zone = route53_backend.get_hosted_zone(self.hosted_zone_id)
diff --git a/tests/test_applicationautoscaling/test_applicationautoscaling.py b/tests/test_applicationautoscaling/test_applicationautoscaling.py
index aed728ab6..6eff526a2 100644
--- a/tests/test_applicationautoscaling/test_applicationautoscaling.py
+++ b/tests/test_applicationautoscaling/test_applicationautoscaling.py
@@ -244,6 +244,11 @@ def test_register_scalable_target_resource_id_variations():
"keyspace/mykeyspace/table/mytable",
"cassandra:table:ReadCapacityUnits",
),
+ (
+ "custom-resource",
+ "https://test-endpoint.amazon.com/ScalableDimension/test-resource",
+ "custom-resource:ResourceType:Property",
+ ),
]
client = boto3.client("application-autoscaling", region_name=DEFAULT_REGION)