Pass the default ECS cluster and raise accurate exceptions (#3522)
* Pass the "default" cluster * Mock ECS exceptions more accurately Moto's mock ECS has drifted fairly far from the actual ECS API in terms of which exceptions it throws. This change begins to bring mock ECS's exceptions in line with actual ECS exceptions. Most notably: - Several custom exceptions have been replaced with their real ECS exception. For example, "{0} is not a cluster" has been replaced with ClusterNotFoundException - Tests have been added to verify (most of) these exceptions work correctly. The test coverage was a little spotty to begin with. - The new exceptions plus the change to pass the "default" cluster exposed a lot of places where mock ECS was behaving incorrectly. For example, the ListTasks action is always scoped to a single cluster in ECS but it listed tasks for all clusters in the mock. I've minimally updated the tests to make them pass, but there's lots of opportunity to refactor both this method's test and its implementation. This does not provide full coverage of exceptions. In general, I ran these operations against actual ECS resources and cross-referenced the documentation to figure out what actual exceptions should be thrown and what the messages should be. Consequently, I didn't update any exceptions that took more than trivial amount of time to reproduce with real resources.
This commit is contained in:
parent
7c7a1222d2
commit
b4e961148f
@ -5,11 +5,9 @@ from moto.core.exceptions import RESTError, JsonRESTError
|
|||||||
class ServiceNotFoundException(RESTError):
|
class ServiceNotFoundException(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, service_name):
|
def __init__(self):
|
||||||
super(ServiceNotFoundException, self).__init__(
|
super(ServiceNotFoundException, self).__init__(
|
||||||
error_type="ServiceNotFoundException",
|
error_type="ServiceNotFoundException", message="Service not found."
|
||||||
message="The service {0} does not exist".format(service_name),
|
|
||||||
template="error_json",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -23,6 +21,15 @@ class TaskDefinitionNotFoundException(JsonRESTError):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RevisionNotFoundException(JsonRESTError):
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(RevisionNotFoundException, self).__init__(
|
||||||
|
error_type="ClientException", message="Revision is missing.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TaskSetNotFoundException(JsonRESTError):
|
class TaskSetNotFoundException(JsonRESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
@ -40,3 +47,12 @@ class ClusterNotFoundException(JsonRESTError):
|
|||||||
super(ClusterNotFoundException, self).__init__(
|
super(ClusterNotFoundException, self).__init__(
|
||||||
error_type="ClientException", message="Cluster not found",
|
error_type="ClientException", message="Cluster not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidParameterException(JsonRESTError):
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(InvalidParameterException, self).__init__(
|
||||||
|
error_type="ClientException", message=message,
|
||||||
|
)
|
||||||
|
@ -18,6 +18,8 @@ from .exceptions import (
|
|||||||
TaskDefinitionNotFoundException,
|
TaskDefinitionNotFoundException,
|
||||||
TaskSetNotFoundException,
|
TaskSetNotFoundException,
|
||||||
ClusterNotFoundException,
|
ClusterNotFoundException,
|
||||||
|
InvalidParameterException,
|
||||||
|
RevisionNotFoundException,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -668,7 +670,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if cluster_name in self.clusters:
|
if cluster_name in self.clusters:
|
||||||
return self.clusters.pop(cluster_name)
|
return self.clusters.pop(cluster_name)
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
|
|
||||||
def register_task_definition(
|
def register_task_definition(
|
||||||
self,
|
self,
|
||||||
@ -713,25 +715,30 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
|
|
||||||
def deregister_task_definition(self, task_definition_str):
|
def deregister_task_definition(self, task_definition_str):
|
||||||
task_definition_name = task_definition_str.split("/")[-1]
|
task_definition_name = task_definition_str.split("/")[-1]
|
||||||
family, revision = task_definition_name.split(":")
|
try:
|
||||||
revision = int(revision)
|
family, revision = task_definition_name.split(":")
|
||||||
|
except ValueError:
|
||||||
|
raise RevisionNotFoundException
|
||||||
|
try:
|
||||||
|
revision = int(revision)
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidParameterException(
|
||||||
|
"Invalid revision number. Number: " + revision
|
||||||
|
)
|
||||||
if (
|
if (
|
||||||
family in self.task_definitions
|
family in self.task_definitions
|
||||||
and revision in self.task_definitions[family]
|
and revision in self.task_definitions[family]
|
||||||
):
|
):
|
||||||
return self.task_definitions[family].pop(revision)
|
return self.task_definitions[family].pop(revision)
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a task_definition".format(task_definition_name))
|
raise TaskDefinitionNotFoundException
|
||||||
|
|
||||||
def run_task(self, cluster_str, task_definition_str, count, overrides, started_by):
|
def run_task(self, cluster_str, task_definition_str, count, overrides, started_by):
|
||||||
if cluster_str:
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
|
||||||
else:
|
|
||||||
cluster_name = "default"
|
|
||||||
if cluster_name in self.clusters:
|
if cluster_name in self.clusters:
|
||||||
cluster = self.clusters[cluster_name]
|
cluster = self.clusters[cluster_name]
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
task_definition = self.describe_task_definition(task_definition_str)
|
task_definition = self.describe_task_definition(task_definition_str)
|
||||||
if cluster_name not in self.tasks:
|
if cluster_name not in self.tasks:
|
||||||
self.tasks[cluster_name] = {}
|
self.tasks[cluster_name] = {}
|
||||||
@ -862,13 +869,13 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if cluster_name in self.clusters:
|
if cluster_name in self.clusters:
|
||||||
cluster = self.clusters[cluster_name]
|
cluster = self.clusters[cluster_name]
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
task_definition = self.describe_task_definition(task_definition_str)
|
task_definition = self.describe_task_definition(task_definition_str)
|
||||||
if cluster_name not in self.tasks:
|
if cluster_name not in self.tasks:
|
||||||
self.tasks[cluster_name] = {}
|
self.tasks[cluster_name] = {}
|
||||||
tasks = []
|
tasks = []
|
||||||
if not container_instances:
|
if not container_instances:
|
||||||
raise Exception("No container instance list provided")
|
raise InvalidParameterException("Container Instances cannot be empty.")
|
||||||
|
|
||||||
container_instance_ids = [x.split("/")[-1] for x in container_instances]
|
container_instance_ids = [x.split("/")[-1] for x in container_instances]
|
||||||
resource_requirements = self._calculate_task_resource_requirements(
|
resource_requirements = self._calculate_task_resource_requirements(
|
||||||
@ -898,9 +905,9 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if cluster_name in self.clusters:
|
if cluster_name in self.clusters:
|
||||||
cluster = self.clusters[cluster_name]
|
cluster = self.clusters[cluster_name]
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
if not tasks:
|
if not tasks:
|
||||||
raise Exception("tasks cannot be empty")
|
raise InvalidParameterException("Tasks cannot be empty.")
|
||||||
response = []
|
response = []
|
||||||
for cluster, cluster_tasks in self.tasks.items():
|
for cluster, cluster_tasks in self.tasks.items():
|
||||||
for task_arn, task in cluster_tasks.items():
|
for task_arn, task in cluster_tasks.items():
|
||||||
@ -929,7 +936,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if cluster_str:
|
if cluster_str:
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
filtered_tasks = list(
|
filtered_tasks = list(
|
||||||
filter(lambda t: cluster_name in t.cluster_arn, filtered_tasks)
|
filter(lambda t: cluster_name in t.cluster_arn, filtered_tasks)
|
||||||
)
|
)
|
||||||
@ -971,10 +978,8 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
def stop_task(self, cluster_str, task_str, reason):
|
def stop_task(self, cluster_str, task_str, reason):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
|
|
||||||
if not task_str:
|
|
||||||
raise Exception("A task ID or ARN is required")
|
|
||||||
task_id = task_str.split("/")[-1]
|
task_id = task_str.split("/")[-1]
|
||||||
tasks = self.tasks.get(cluster_name, None)
|
tasks = self.tasks.get(cluster_name, None)
|
||||||
if not tasks:
|
if not tasks:
|
||||||
@ -1011,7 +1016,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if cluster_name in self.clusters:
|
if cluster_name in self.clusters:
|
||||||
cluster = self.clusters[cluster_name]
|
cluster = self.clusters[cluster_name]
|
||||||
else:
|
else:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
if task_definition_str is not None:
|
if task_definition_str is not None:
|
||||||
task_definition = self.describe_task_definition(task_definition_str)
|
task_definition = self.describe_task_definition(task_definition_str)
|
||||||
else:
|
else:
|
||||||
@ -1069,6 +1074,8 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
self, cluster_str, service_str, task_definition_str, desired_count
|
self, cluster_str, service_str, task_definition_str, desired_count
|
||||||
):
|
):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
|
if cluster_name not in self.clusters:
|
||||||
|
raise ClusterNotFoundException
|
||||||
service_name = service_str.split("/")[-1]
|
service_name = service_str.split("/")[-1]
|
||||||
cluster_service_pair = "{0}:{1}".format(cluster_name, service_name)
|
cluster_service_pair = "{0}:{1}".format(cluster_name, service_name)
|
||||||
if cluster_service_pair in self.services:
|
if cluster_service_pair in self.services:
|
||||||
@ -1081,22 +1088,23 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
self.services[cluster_service_pair].desired_count = desired_count
|
self.services[cluster_service_pair].desired_count = desired_count
|
||||||
return self.services[cluster_service_pair]
|
return self.services[cluster_service_pair]
|
||||||
else:
|
else:
|
||||||
raise ServiceNotFoundException(service_name)
|
raise ServiceNotFoundException
|
||||||
|
|
||||||
def delete_service(self, cluster_name, service_name):
|
def delete_service(self, cluster_name, service_name):
|
||||||
cluster_service_pair = "{0}:{1}".format(cluster_name, service_name)
|
cluster_service_pair = "{0}:{1}".format(cluster_name, service_name)
|
||||||
|
if cluster_name not in self.clusters:
|
||||||
|
raise ClusterNotFoundException
|
||||||
|
|
||||||
if cluster_service_pair in self.services:
|
if cluster_service_pair in self.services:
|
||||||
service = self.services[cluster_service_pair]
|
service = self.services[cluster_service_pair]
|
||||||
if service.desired_count > 0:
|
if service.desired_count > 0:
|
||||||
raise Exception("Service must have desiredCount=0")
|
raise InvalidParameterException(
|
||||||
|
"The service cannot be stopped while it is scaled above 0."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.services.pop(cluster_service_pair)
|
return self.services.pop(cluster_service_pair)
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise ServiceNotFoundException
|
||||||
"cluster {0} or service {1} does not exist".format(
|
|
||||||
cluster_name, service_name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def register_container_instance(self, cluster_str, ec2_instance_id):
|
def register_container_instance(self, cluster_str, ec2_instance_id):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
@ -1125,11 +1133,9 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
def describe_container_instances(self, cluster_str, list_container_instance_ids):
|
def describe_container_instances(self, cluster_str, list_container_instance_ids):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
if not list_container_instance_ids:
|
if not list_container_instance_ids:
|
||||||
raise JsonRESTError(
|
raise InvalidParameterException("Container Instances cannot be empty.")
|
||||||
"InvalidParameterException", "Container instance cannot be empty"
|
|
||||||
)
|
|
||||||
failures = []
|
failures = []
|
||||||
container_instance_objects = []
|
container_instance_objects = []
|
||||||
for container_instance_id in list_container_instance_ids:
|
for container_instance_id in list_container_instance_ids:
|
||||||
@ -1153,12 +1159,11 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
):
|
):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
status = status.upper()
|
status = status.upper()
|
||||||
if status not in ["ACTIVE", "DRAINING"]:
|
if status not in ["ACTIVE", "DRAINING"]:
|
||||||
raise Exception(
|
raise InvalidParameterException(
|
||||||
"An error occurred (InvalidParameterException) when calling the UpdateContainerInstancesState operation: \
|
"Container instance status should be one of [ACTIVE, DRAINING]"
|
||||||
Container instances status should be one of [ACTIVE,DRAINING]"
|
|
||||||
)
|
)
|
||||||
failures = []
|
failures = []
|
||||||
container_instance_objects = []
|
container_instance_objects = []
|
||||||
@ -1208,7 +1213,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
failures = []
|
failures = []
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
container_instance_id = container_instance_str.split("/")[-1]
|
container_instance_id = container_instance_str.split("/")[-1]
|
||||||
container_instance = self.container_instances[cluster_name].get(
|
container_instance = self.container_instances[cluster_name].get(
|
||||||
container_instance_id
|
container_instance_id
|
||||||
@ -1232,7 +1237,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
def _respond_to_cluster_state_update(self, cluster_str):
|
def _respond_to_cluster_state_update(self, cluster_str):
|
||||||
cluster_name = cluster_str.split("/")[-1]
|
cluster_name = cluster_str.split("/")[-1]
|
||||||
if cluster_name not in self.clusters:
|
if cluster_name not in self.clusters:
|
||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise ClusterNotFoundException
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def put_attributes(self, cluster_name, attributes=None):
|
def put_attributes(self, cluster_name, attributes=None):
|
||||||
@ -1240,9 +1245,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
raise ClusterNotFoundException
|
raise ClusterNotFoundException
|
||||||
|
|
||||||
if attributes is None:
|
if attributes is None:
|
||||||
raise JsonRESTError(
|
raise InvalidParameterException("attributes can not be empty")
|
||||||
"InvalidParameterException", "attributes value is required"
|
|
||||||
)
|
|
||||||
|
|
||||||
for attr in attributes:
|
for attr in attributes:
|
||||||
self._put_attribute(
|
self._put_attribute(
|
||||||
@ -1413,7 +1416,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
if service.arn == resource_arn:
|
if service.arn == resource_arn:
|
||||||
return service.tags
|
return service.tags
|
||||||
else:
|
else:
|
||||||
raise ServiceNotFoundException(service_name=parsed_arn["id"])
|
raise ServiceNotFoundException
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _get_last_task_definition_revision_id(self, family):
|
def _get_last_task_definition_revision_id(self, family):
|
||||||
@ -1430,7 +1433,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
service.tags = self._merge_tags(service.tags, tags)
|
service.tags = self._merge_tags(service.tags, tags)
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
raise ServiceNotFoundException(service_name=parsed_arn["id"])
|
raise ServiceNotFoundException
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _merge_tags(self, existing_tags, new_tags):
|
def _merge_tags(self, existing_tags, new_tags):
|
||||||
@ -1456,7 +1459,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
]
|
]
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
raise ServiceNotFoundException(service_name=parsed_arn["id"])
|
raise ServiceNotFoundException
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def create_task_set(
|
def create_task_set(
|
||||||
@ -1497,7 +1500,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
|
|
||||||
service_obj = self.services.get("{0}:{1}".format(cluster_name, service_name))
|
service_obj = self.services.get("{0}:{1}".format(cluster_name, service_name))
|
||||||
if not service_obj:
|
if not service_obj:
|
||||||
raise ServiceNotFoundException(service_name=service_name)
|
raise ServiceNotFoundException
|
||||||
|
|
||||||
cluster_obj = self.clusters.get(cluster_name)
|
cluster_obj = self.clusters.get(cluster_name)
|
||||||
if not cluster_obj:
|
if not cluster_obj:
|
||||||
@ -1522,7 +1525,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
|
|
||||||
service_obj = self.services.get(service_key)
|
service_obj = self.services.get(service_key)
|
||||||
if not service_obj:
|
if not service_obj:
|
||||||
raise ServiceNotFoundException(service_name=service_name)
|
raise ServiceNotFoundException
|
||||||
|
|
||||||
cluster_obj = self.clusters.get(cluster_name)
|
cluster_obj = self.clusters.get(cluster_name)
|
||||||
if not cluster_obj:
|
if not cluster_obj:
|
||||||
|
@ -100,7 +100,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"taskDefinition": task_definition.response_object})
|
return json.dumps({"taskDefinition": task_definition.response_object})
|
||||||
|
|
||||||
def run_task(self):
|
def run_task(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
overrides = self._get_param("overrides")
|
overrides = self._get_param("overrides")
|
||||||
task_definition_str = self._get_param("taskDefinition")
|
task_definition_str = self._get_param("taskDefinition")
|
||||||
count = self._get_int_param("count")
|
count = self._get_int_param("count")
|
||||||
@ -113,7 +113,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def describe_tasks(self):
|
def describe_tasks(self):
|
||||||
cluster = self._get_param("cluster")
|
cluster = self._get_param("cluster", "default")
|
||||||
tasks = self._get_param("tasks")
|
tasks = self._get_param("tasks")
|
||||||
data = self.ecs_backend.describe_tasks(cluster, tasks)
|
data = self.ecs_backend.describe_tasks(cluster, tasks)
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
@ -121,7 +121,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def start_task(self):
|
def start_task(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
overrides = self._get_param("overrides")
|
overrides = self._get_param("overrides")
|
||||||
task_definition_str = self._get_param("taskDefinition")
|
task_definition_str = self._get_param("taskDefinition")
|
||||||
container_instances = self._get_param("containerInstances")
|
container_instances = self._get_param("containerInstances")
|
||||||
@ -134,7 +134,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def list_tasks(self):
|
def list_tasks(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
container_instance = self._get_param("containerInstance")
|
container_instance = self._get_param("containerInstance")
|
||||||
family = self._get_param("family")
|
family = self._get_param("family")
|
||||||
started_by = self._get_param("startedBy")
|
started_by = self._get_param("startedBy")
|
||||||
@ -151,14 +151,14 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"taskArns": task_arns})
|
return json.dumps({"taskArns": task_arns})
|
||||||
|
|
||||||
def stop_task(self):
|
def stop_task(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
task = self._get_param("task")
|
task = self._get_param("task")
|
||||||
reason = self._get_param("reason")
|
reason = self._get_param("reason")
|
||||||
task = self.ecs_backend.stop_task(cluster_str, task, reason)
|
task = self.ecs_backend.stop_task(cluster_str, task, reason)
|
||||||
return json.dumps({"task": task.response_object})
|
return json.dumps({"task": task.response_object})
|
||||||
|
|
||||||
def create_service(self):
|
def create_service(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_name = self._get_param("serviceName")
|
service_name = self._get_param("serviceName")
|
||||||
task_definition_str = self._get_param("taskDefinition")
|
task_definition_str = self._get_param("taskDefinition")
|
||||||
desired_count = self._get_int_param("desiredCount")
|
desired_count = self._get_int_param("desiredCount")
|
||||||
@ -179,7 +179,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"service": service.response_object})
|
return json.dumps({"service": service.response_object})
|
||||||
|
|
||||||
def list_services(self):
|
def list_services(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
scheduling_strategy = self._get_param("schedulingStrategy")
|
scheduling_strategy = self._get_param("schedulingStrategy")
|
||||||
service_arns = self.ecs_backend.list_services(cluster_str, scheduling_strategy)
|
service_arns = self.ecs_backend.list_services(cluster_str, scheduling_strategy)
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
@ -191,7 +191,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def describe_services(self):
|
def describe_services(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_names = self._get_param("services")
|
service_names = self._get_param("services")
|
||||||
services = self.ecs_backend.describe_services(cluster_str, service_names)
|
services = self.ecs_backend.describe_services(cluster_str, service_names)
|
||||||
resp = {
|
resp = {
|
||||||
@ -206,7 +206,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps(resp)
|
return json.dumps(resp)
|
||||||
|
|
||||||
def update_service(self):
|
def update_service(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_name = self._get_param("service")
|
service_name = self._get_param("service")
|
||||||
task_definition = self._get_param("taskDefinition")
|
task_definition = self._get_param("taskDefinition")
|
||||||
desired_count = self._get_int_param("desiredCount")
|
desired_count = self._get_int_param("desiredCount")
|
||||||
@ -217,12 +217,12 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
|
|
||||||
def delete_service(self):
|
def delete_service(self):
|
||||||
service_name = self._get_param("service")
|
service_name = self._get_param("service")
|
||||||
cluster_name = self._get_param("cluster")
|
cluster_name = self._get_param("cluster", "default")
|
||||||
service = self.ecs_backend.delete_service(cluster_name, service_name)
|
service = self.ecs_backend.delete_service(cluster_name, service_name)
|
||||||
return json.dumps({"service": service.response_object})
|
return json.dumps({"service": service.response_object})
|
||||||
|
|
||||||
def register_container_instance(self):
|
def register_container_instance(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
instance_identity_document_str = self._get_param("instanceIdentityDocument")
|
instance_identity_document_str = self._get_param("instanceIdentityDocument")
|
||||||
instance_identity_document = json.loads(instance_identity_document_str)
|
instance_identity_document = json.loads(instance_identity_document_str)
|
||||||
ec2_instance_id = instance_identity_document["instanceId"]
|
ec2_instance_id = instance_identity_document["instanceId"]
|
||||||
@ -232,9 +232,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"containerInstance": container_instance.response_object})
|
return json.dumps({"containerInstance": container_instance.response_object})
|
||||||
|
|
||||||
def deregister_container_instance(self):
|
def deregister_container_instance(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
if not cluster_str:
|
|
||||||
cluster_str = "default"
|
|
||||||
container_instance_str = self._get_param("containerInstance")
|
container_instance_str = self._get_param("containerInstance")
|
||||||
force = self._get_param("force")
|
force = self._get_param("force")
|
||||||
container_instance, failures = self.ecs_backend.deregister_container_instance(
|
container_instance, failures = self.ecs_backend.deregister_container_instance(
|
||||||
@ -243,12 +241,12 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"containerInstance": container_instance.response_object})
|
return json.dumps({"containerInstance": container_instance.response_object})
|
||||||
|
|
||||||
def list_container_instances(self):
|
def list_container_instances(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
container_instance_arns = self.ecs_backend.list_container_instances(cluster_str)
|
container_instance_arns = self.ecs_backend.list_container_instances(cluster_str)
|
||||||
return json.dumps({"containerInstanceArns": container_instance_arns})
|
return json.dumps({"containerInstanceArns": container_instance_arns})
|
||||||
|
|
||||||
def describe_container_instances(self):
|
def describe_container_instances(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
list_container_instance_arns = self._get_param("containerInstances")
|
list_container_instance_arns = self._get_param("containerInstances")
|
||||||
container_instances, failures = self.ecs_backend.describe_container_instances(
|
container_instances, failures = self.ecs_backend.describe_container_instances(
|
||||||
cluster_str, list_container_instance_arns
|
cluster_str, list_container_instance_arns
|
||||||
@ -263,7 +261,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def update_container_instances_state(self):
|
def update_container_instances_state(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
list_container_instance_arns = self._get_param("containerInstances")
|
list_container_instance_arns = self._get_param("containerInstances")
|
||||||
status_str = self._get_param("status")
|
status_str = self._get_param("status")
|
||||||
(
|
(
|
||||||
@ -312,7 +310,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"attributes": formatted_results})
|
return json.dumps({"attributes": formatted_results})
|
||||||
|
|
||||||
def delete_attributes(self):
|
def delete_attributes(self):
|
||||||
cluster_name = self._get_param("cluster")
|
cluster_name = self._get_param("cluster", "default")
|
||||||
attributes = self._get_param("attributes")
|
attributes = self._get_param("attributes")
|
||||||
|
|
||||||
self.ecs_backend.delete_attributes(cluster_name, attributes)
|
self.ecs_backend.delete_attributes(cluster_name, attributes)
|
||||||
@ -359,7 +357,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
|
|
||||||
def create_task_set(self):
|
def create_task_set(self):
|
||||||
service_str = self._get_param("service")
|
service_str = self._get_param("service")
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
task_definition = self._get_param("taskDefinition")
|
task_definition = self._get_param("taskDefinition")
|
||||||
external_id = self._get_param("externalId")
|
external_id = self._get_param("externalId")
|
||||||
network_configuration = self._get_param("networkConfiguration")
|
network_configuration = self._get_param("networkConfiguration")
|
||||||
@ -389,7 +387,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"taskSet": task_set.response_object})
|
return json.dumps({"taskSet": task_set.response_object})
|
||||||
|
|
||||||
def describe_task_sets(self):
|
def describe_task_sets(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_str = self._get_param("service")
|
service_str = self._get_param("service")
|
||||||
task_sets = self._get_param("taskSets")
|
task_sets = self._get_param("taskSets")
|
||||||
include = self._get_param("include", [])
|
include = self._get_param("include", [])
|
||||||
@ -414,7 +412,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"taskSet": task_set.response_object})
|
return json.dumps({"taskSet": task_set.response_object})
|
||||||
|
|
||||||
def update_task_set(self):
|
def update_task_set(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_str = self._get_param("service")
|
service_str = self._get_param("service")
|
||||||
task_set = self._get_param("taskSet")
|
task_set = self._get_param("taskSet")
|
||||||
scale = self._get_param("scale")
|
scale = self._get_param("scale")
|
||||||
@ -425,7 +423,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({"taskSet": task_set.response_object})
|
return json.dumps({"taskSet": task_set.response_object})
|
||||||
|
|
||||||
def update_service_primary_task_set(self):
|
def update_service_primary_task_set(self):
|
||||||
cluster_str = self._get_param("cluster")
|
cluster_str = self._get_param("cluster", "default")
|
||||||
service_str = self._get_param("service")
|
service_str = self._get_param("service")
|
||||||
primary_task_set = self._get_param("primaryTaskSet")
|
primary_task_set = self._get_param("primaryTaskSet")
|
||||||
|
|
||||||
|
@ -10,6 +10,13 @@ from uuid import UUID
|
|||||||
|
|
||||||
from moto import mock_ecs
|
from moto import mock_ecs
|
||||||
from moto import mock_ec2
|
from moto import mock_ec2
|
||||||
|
from moto.ecs.exceptions import (
|
||||||
|
ClusterNotFoundException,
|
||||||
|
ServiceNotFoundException,
|
||||||
|
InvalidParameterException,
|
||||||
|
TaskDefinitionNotFoundException,
|
||||||
|
RevisionNotFoundException,
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@ -73,6 +80,14 @@ def test_delete_cluster():
|
|||||||
len(response["clusterArns"]).should.equal(0)
|
len(response["clusterArns"]).should.equal(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_delete_cluster_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
client.delete_cluster.when.called_with(cluster="not_a_cluster").should.throw(
|
||||||
|
ClientError, ClusterNotFoundException().message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_register_task_definition():
|
def test_register_task_definition():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
@ -347,6 +362,23 @@ def test_deregister_task_definition():
|
|||||||
].should.equal("json-file")
|
].should.equal("json-file")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_deregister_task_definition():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
client.deregister_task_definition.when.called_with(
|
||||||
|
taskDefinition="fake_task"
|
||||||
|
).should.throw(ClientError, RevisionNotFoundException().message)
|
||||||
|
client.deregister_task_definition.when.called_with(
|
||||||
|
taskDefinition="fake_task:foo"
|
||||||
|
).should.throw(
|
||||||
|
ClientError,
|
||||||
|
InvalidParameterException("Invalid revision number. Number: foo").message,
|
||||||
|
)
|
||||||
|
client.deregister_task_definition.when.called_with(
|
||||||
|
taskDefinition="fake_task:1"
|
||||||
|
).should.throw(ClientError, TaskDefinitionNotFoundException().message)
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_create_service():
|
def test_create_service():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
@ -751,17 +783,56 @@ def test_delete_service():
|
|||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_update_non_existent_service():
|
def test_delete_service_exceptions():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
try:
|
|
||||||
client.update_service(
|
# Raises ClusterNotFoundException because "default" is not a cluster
|
||||||
cluster="my-clustet", service="my-service", desiredCount=0
|
client.delete_service.when.called_with(service="not_as_service").should.throw(
|
||||||
)
|
ClientError, ClusterNotFoundException().message
|
||||||
except ClientError as exc:
|
)
|
||||||
error_code = exc.response["Error"]["Code"]
|
|
||||||
error_code.should.equal("ServiceNotFoundException")
|
_ = client.create_cluster()
|
||||||
else:
|
client.delete_service.when.called_with(service="not_as_service").should.throw(
|
||||||
raise Exception("Didn't raise ClientError")
|
ClientError, ServiceNotFoundException().message
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.register_task_definition(
|
||||||
|
family="test_ecs_task",
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
"name": "hello_world",
|
||||||
|
"image": "docker/hello-world:latest",
|
||||||
|
"cpu": 1024,
|
||||||
|
"memory": 400,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.create_service(
|
||||||
|
serviceName="test_ecs_service", taskDefinition="test_ecs_task", desiredCount=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
client.delete_service.when.called_with(service="test_ecs_service").should.throw(
|
||||||
|
ClientError,
|
||||||
|
InvalidParameterException(
|
||||||
|
"The service cannot be stopped while it is scaled above 0."
|
||||||
|
).message,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_update_service_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
|
||||||
|
client.update_service.when.called_with(
|
||||||
|
service="not_a_service", desiredCount=0
|
||||||
|
).should.throw(ClientError, ClusterNotFoundException().message)
|
||||||
|
|
||||||
|
_ = client.create_cluster()
|
||||||
|
|
||||||
|
client.update_service.when.called_with(
|
||||||
|
service="not_a_service", desiredCount=0
|
||||||
|
).should.throw(ClientError, ServiceNotFoundException().message)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@ -958,6 +1029,23 @@ def test_describe_container_instances():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_describe_container_instances_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
|
||||||
|
client.describe_container_instances.when.called_with(
|
||||||
|
containerInstances=[]
|
||||||
|
).should.throw(ClientError, ClusterNotFoundException().message)
|
||||||
|
|
||||||
|
_ = client.create_cluster()
|
||||||
|
client.describe_container_instances.when.called_with(
|
||||||
|
containerInstances=[]
|
||||||
|
).should.throw(
|
||||||
|
ClientError,
|
||||||
|
InvalidParameterException("Container Instances cannot be empty.").message,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_update_container_instances_state():
|
def test_update_container_instances_state():
|
||||||
@ -1213,6 +1301,26 @@ def test_run_task_default_cluster():
|
|||||||
response["tasks"][0]["stoppedReason"].should.equal("")
|
response["tasks"][0]["stoppedReason"].should.equal("")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_run_task_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
_ = client.register_task_definition(
|
||||||
|
family="test_ecs_task",
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
"name": "hello_world",
|
||||||
|
"image": "docker/hello-world:latest",
|
||||||
|
"cpu": 1024,
|
||||||
|
"memory": 400,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
client.run_task.when.called_with(
|
||||||
|
cluster="not_a_cluster", taskDefinition="test_ecs_task"
|
||||||
|
).should.throw(ClientError, ClusterNotFoundException().message)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_start_task():
|
def test_start_task():
|
||||||
@ -1287,15 +1395,40 @@ def test_start_task():
|
|||||||
response["tasks"][0]["stoppedReason"].should.equal("")
|
response["tasks"][0]["stoppedReason"].should.equal("")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_start_task_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
_ = client.register_task_definition(
|
||||||
|
family="test_ecs_task",
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
"name": "hello_world",
|
||||||
|
"image": "docker/hello-world:latest",
|
||||||
|
"cpu": 1024,
|
||||||
|
"memory": 400,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
client.start_task.when.called_with(
|
||||||
|
taskDefinition="test_ecs_task", containerInstances=["not_a_container_instance"]
|
||||||
|
).should.throw(ClientError, ClusterNotFoundException().message)
|
||||||
|
|
||||||
|
_ = client.create_cluster()
|
||||||
|
client.start_task.when.called_with(
|
||||||
|
taskDefinition="test_ecs_task", containerInstances=[]
|
||||||
|
).should.throw(
|
||||||
|
ClientError, InvalidParameterException("Container Instances cannot be empty.")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_list_tasks():
|
def test_list_tasks():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||||
|
|
||||||
test_cluster_name = "test_ecs_cluster"
|
_ = client.create_cluster()
|
||||||
|
|
||||||
_ = client.create_cluster(clusterName=test_cluster_name)
|
|
||||||
|
|
||||||
test_instance = ec2.create_instances(
|
test_instance = ec2.create_instances(
|
||||||
ImageId="ami-1234abcd", MinCount=1, MaxCount=1
|
ImageId="ami-1234abcd", MinCount=1, MaxCount=1
|
||||||
@ -1306,10 +1439,10 @@ def test_list_tasks():
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = client.register_container_instance(
|
_ = client.register_container_instance(
|
||||||
cluster=test_cluster_name, instanceIdentityDocument=instance_id_document
|
instanceIdentityDocument=instance_id_document
|
||||||
)
|
)
|
||||||
|
|
||||||
container_instances = client.list_container_instances(cluster=test_cluster_name)
|
container_instances = client.list_container_instances()
|
||||||
container_instance_id = container_instances["containerInstanceArns"][0].split("/")[
|
container_instance_id = container_instances["containerInstanceArns"][0].split("/")[
|
||||||
-1
|
-1
|
||||||
]
|
]
|
||||||
@ -1332,7 +1465,6 @@ def test_list_tasks():
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = client.start_task(
|
_ = client.start_task(
|
||||||
cluster="test_ecs_cluster",
|
|
||||||
taskDefinition="test_ecs_task",
|
taskDefinition="test_ecs_task",
|
||||||
overrides={},
|
overrides={},
|
||||||
containerInstances=[container_instance_id],
|
containerInstances=[container_instance_id],
|
||||||
@ -1340,7 +1472,6 @@ def test_list_tasks():
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = client.start_task(
|
_ = client.start_task(
|
||||||
cluster="test_ecs_cluster",
|
|
||||||
taskDefinition="test_ecs_task",
|
taskDefinition="test_ecs_task",
|
||||||
overrides={},
|
overrides={},
|
||||||
containerInstances=[container_instance_id],
|
containerInstances=[container_instance_id],
|
||||||
@ -1348,12 +1479,17 @@ def test_list_tasks():
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert len(client.list_tasks()["taskArns"]).should.equal(2)
|
assert len(client.list_tasks()["taskArns"]).should.equal(2)
|
||||||
assert len(client.list_tasks(cluster="test_ecs_cluster")["taskArns"]).should.equal(
|
|
||||||
2
|
|
||||||
)
|
|
||||||
assert len(client.list_tasks(startedBy="foo")["taskArns"]).should.equal(1)
|
assert len(client.list_tasks(startedBy="foo")["taskArns"]).should.equal(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_list_tasks_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
client.list_tasks.when.called_with(cluster="not_a_cluster").should.throw(
|
||||||
|
ClientError, ClusterNotFoundException().message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_describe_tasks():
|
def test_describe_tasks():
|
||||||
@ -1416,6 +1552,20 @@ def test_describe_tasks():
|
|||||||
len(response["tasks"]).should.equal(1)
|
len(response["tasks"]).should.equal(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_describe_tasks_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
|
||||||
|
client.describe_tasks.when.called_with(tasks=[]).should.throw(
|
||||||
|
ClientError, ClusterNotFoundException().message
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = client.create_cluster()
|
||||||
|
client.describe_tasks.when.called_with(tasks=[]).should.throw(
|
||||||
|
ClientError, InvalidParameterException("Tasks cannot be empty.").message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def describe_task_definition():
|
def describe_task_definition():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
@ -1499,6 +1649,15 @@ def test_stop_task():
|
|||||||
stop_response["task"]["stoppedReason"].should.equal("moto testing")
|
stop_response["task"]["stoppedReason"].should.equal("moto testing")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_stop_task_exceptions():
|
||||||
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
|
|
||||||
|
client.stop_task.when.called_with(task="fake_task").should.throw(
|
||||||
|
ClientError, ClusterNotFoundException().message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_resource_reservation_and_release():
|
def test_resource_reservation_and_release():
|
||||||
@ -2160,13 +2319,14 @@ def test_list_tags_for_resource():
|
|||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_list_tags_for_resource_unknown():
|
def test_list_tags_exceptions():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
task_definition_arn = "arn:aws:ecs:us-east-1:012345678910:task-definition/unknown:1"
|
client.list_tags_for_resource.when.called_with(
|
||||||
try:
|
resourceArn="arn:aws:ecs:us-east-1:012345678910:service/fake_service:1"
|
||||||
client.list_tags_for_resource(resourceArn=task_definition_arn)
|
).should.throw(ClientError, ServiceNotFoundException().message)
|
||||||
except ClientError as err:
|
client.list_tags_for_resource.when.called_with(
|
||||||
err.response["Error"]["Code"].should.equal("ClientException")
|
resourceArn="arn:aws:ecs:us-east-1:012345678910:task-definition/fake_task:1"
|
||||||
|
).should.throw(ClientError, TaskDefinitionNotFoundException().message)
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
@ -2208,16 +2368,6 @@ def test_list_tags_for_resource_ecs_service():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
|
||||||
def test_list_tags_for_resource_unknown_service():
|
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
|
||||||
service_arn = "arn:aws:ecs:us-east-1:012345678910:service/unknown:1"
|
|
||||||
try:
|
|
||||||
client.list_tags_for_resource(resourceArn=service_arn)
|
|
||||||
except ClientError as err:
|
|
||||||
err.response["Error"]["Code"].should.equal("ServiceNotFoundException")
|
|
||||||
|
|
||||||
|
|
||||||
@mock_ecs
|
@mock_ecs
|
||||||
def test_ecs_service_tag_resource():
|
def test_ecs_service_tag_resource():
|
||||||
client = boto3.client("ecs", region_name="us-east-1")
|
client = boto3.client("ecs", region_name="us-east-1")
|
||||||
@ -2816,30 +2966,68 @@ def test_list_tasks_with_filters():
|
|||||||
startedBy="bar",
|
startedBy="bar",
|
||||||
)
|
)
|
||||||
|
|
||||||
len(ecs.list_tasks()["taskArns"]).should.equal(3)
|
|
||||||
|
|
||||||
len(ecs.list_tasks(cluster="test_cluster_1")["taskArns"]).should.equal(2)
|
len(ecs.list_tasks(cluster="test_cluster_1")["taskArns"]).should.equal(2)
|
||||||
len(ecs.list_tasks(cluster="test_cluster_2")["taskArns"]).should.equal(1)
|
len(ecs.list_tasks(cluster="test_cluster_2")["taskArns"]).should.equal(1)
|
||||||
|
|
||||||
len(ecs.list_tasks(containerInstance="bad-id")["taskArns"]).should.equal(0)
|
len(
|
||||||
len(ecs.list_tasks(containerInstance=container_id_1)["taskArns"]).should.equal(2)
|
ecs.list_tasks(cluster="test_cluster_1", containerInstance="bad-id")["taskArns"]
|
||||||
len(ecs.list_tasks(containerInstance=container_id_2)["taskArns"]).should.equal(1)
|
).should.equal(0)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_1", containerInstance=container_id_1)[
|
||||||
|
"taskArns"
|
||||||
|
]
|
||||||
|
).should.equal(2)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_2", containerInstance=container_id_2)[
|
||||||
|
"taskArns"
|
||||||
|
]
|
||||||
|
).should.equal(1)
|
||||||
|
|
||||||
len(ecs.list_tasks(family="non-existent-family")["taskArns"]).should.equal(0)
|
len(
|
||||||
len(ecs.list_tasks(family="test_task_def_1")["taskArns"]).should.equal(2)
|
ecs.list_tasks(cluster="test_cluster_1", family="non-existent-family")[
|
||||||
len(ecs.list_tasks(family="test_task_def_2")["taskArns"]).should.equal(1)
|
"taskArns"
|
||||||
|
]
|
||||||
|
).should.equal(0)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_1", family="test_task_def_1")["taskArns"]
|
||||||
|
).should.equal(2)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_2", family="test_task_def_2")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
|
|
||||||
len(ecs.list_tasks(startedBy="non-existent-entity")["taskArns"]).should.equal(0)
|
len(
|
||||||
len(ecs.list_tasks(startedBy="foo")["taskArns"]).should.equal(2)
|
ecs.list_tasks(cluster="test_cluster_1", startedBy="non-existent-entity")[
|
||||||
len(ecs.list_tasks(startedBy="bar")["taskArns"]).should.equal(1)
|
"taskArns"
|
||||||
|
]
|
||||||
|
).should.equal(0)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_1", startedBy="foo")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_1", startedBy="bar")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_2", startedBy="foo")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
|
|
||||||
len(ecs.list_tasks(desiredStatus="RUNNING")["taskArns"]).should.equal(3)
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_1", desiredStatus="RUNNING")["taskArns"]
|
||||||
|
).should.equal(2)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_2", desiredStatus="RUNNING")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
_ = ecs.stop_task(cluster="test_cluster_2", task=task_to_stop, reason="for testing")
|
_ = ecs.stop_task(cluster="test_cluster_2", task=task_to_stop, reason="for testing")
|
||||||
len(ecs.list_tasks(desiredStatus="RUNNING")["taskArns"]).should.equal(2)
|
len(
|
||||||
len(ecs.list_tasks(desiredStatus="STOPPED")["taskArns"]).should.equal(1)
|
ecs.list_tasks(cluster="test_cluster_1", desiredStatus="RUNNING")["taskArns"]
|
||||||
|
).should.equal(2)
|
||||||
|
len(
|
||||||
|
ecs.list_tasks(cluster="test_cluster_2", desiredStatus="STOPPED")["taskArns"]
|
||||||
|
).should.equal(1)
|
||||||
|
|
||||||
resp = ecs.list_tasks(cluster="test_cluster_1", startedBy="foo")
|
resp = ecs.list_tasks(cluster="test_cluster_1", startedBy="foo")
|
||||||
len(resp["taskArns"]).should.equal(1)
|
len(resp["taskArns"]).should.equal(1)
|
||||||
|
|
||||||
resp = ecs.list_tasks(containerInstance=container_id_1, startedBy="bar")
|
resp = ecs.list_tasks(
|
||||||
|
cluster="test_cluster_1", containerInstance=container_id_1, startedBy="bar"
|
||||||
|
)
|
||||||
len(resp["taskArns"]).should.equal(1)
|
len(resp["taskArns"]).should.equal(1)
|
||||||
|
Loading…
Reference in New Issue
Block a user