ECS: allow ecs service to transition to arbitrary running task count (#6289)
This commit is contained in:
parent
6b2ee153e6
commit
60065b3cf8
@ -2,6 +2,7 @@ import re
|
||||
from copy import copy
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Dict, Iterator, List, Optional, Tuple
|
||||
from os import getenv
|
||||
|
||||
from moto import settings
|
||||
from moto.core import BaseBackend, BackendDict, BaseModel, CloudFormationModel
|
||||
@ -488,6 +489,14 @@ class CapacityProviderFailure(BaseObject):
|
||||
|
||||
|
||||
class Service(BaseObject, CloudFormationModel):
|
||||
"""Set the environment variable MOTO_ECS_SERVICE_RUNNING to a number of running tasks you want
|
||||
the service to transition to, ie if set to 2:
|
||||
|
||||
MOTO_ECS_SERVICE_RUNNING=2
|
||||
|
||||
then describe_services call to return runningCount of the service AND deployment to 2
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cluster: Cluster,
|
||||
@ -507,7 +516,6 @@ class Service(BaseObject, CloudFormationModel):
|
||||
self.cluster_arn = cluster.arn
|
||||
self.name = service_name
|
||||
self.status = "ACTIVE"
|
||||
self.running_count = 0
|
||||
self.task_definition = task_definition.arn if task_definition else None
|
||||
self.desired_count = desired_count
|
||||
self.task_sets: List[TaskSet] = []
|
||||
@ -515,6 +523,25 @@ class Service(BaseObject, CloudFormationModel):
|
||||
self.events: List[Dict[str, Any]] = []
|
||||
self.launch_type = launch_type
|
||||
self.service_registries = service_registries or []
|
||||
self.load_balancers = load_balancers if load_balancers is not None else []
|
||||
self.scheduling_strategy = (
|
||||
scheduling_strategy if scheduling_strategy is not None else "REPLICA"
|
||||
)
|
||||
self.platform_version = platform_version
|
||||
self.tags = tags if tags is not None else []
|
||||
self.region_name = cluster.region_name
|
||||
self._account_id = backend.account_id
|
||||
self._backend = backend
|
||||
|
||||
try:
|
||||
# negative running count not allowed, set to 0 if so
|
||||
ecs_running_count = max(int(getenv("MOTO_ECS_SERVICE_RUNNING", 0)), 0)
|
||||
except ValueError:
|
||||
# Unable to parse value of MOTO_ECS_SERVICE_RUNNING as an integer, set to default 0
|
||||
ecs_running_count = 0
|
||||
|
||||
self.running_count = ecs_running_count
|
||||
self.pending_count = desired_count - ecs_running_count
|
||||
if self.deployment_controller["type"] == "ECS":
|
||||
self.deployments = [
|
||||
{
|
||||
@ -522,8 +549,8 @@ class Service(BaseObject, CloudFormationModel):
|
||||
"desiredCount": self.desired_count,
|
||||
"id": f"ecs-svc/{mock_random.randint(0, 32**12)}",
|
||||
"launchType": self.launch_type,
|
||||
"pendingCount": self.desired_count,
|
||||
"runningCount": 0,
|
||||
"pendingCount": self.pending_count,
|
||||
"runningCount": ecs_running_count,
|
||||
"status": "PRIMARY",
|
||||
"taskDefinition": self.task_definition,
|
||||
"updatedAt": datetime.now(timezone.utc),
|
||||
@ -531,16 +558,6 @@ class Service(BaseObject, CloudFormationModel):
|
||||
]
|
||||
else:
|
||||
self.deployments = []
|
||||
self.load_balancers = load_balancers if load_balancers is not None else []
|
||||
self.scheduling_strategy = (
|
||||
scheduling_strategy if scheduling_strategy is not None else "REPLICA"
|
||||
)
|
||||
self.platform_version = platform_version
|
||||
self.tags = tags if tags is not None else []
|
||||
self.pending_count = 0
|
||||
self.region_name = cluster.region_name
|
||||
self._account_id = backend.account_id
|
||||
self._backend = backend
|
||||
|
||||
@property
|
||||
def arn(self) -> str:
|
||||
@ -1641,6 +1658,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
# It is only deleted later on
|
||||
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecs.html#ECS.Client.delete_service
|
||||
service.status = "INACTIVE"
|
||||
service.pending_count = 0
|
||||
return service
|
||||
|
||||
def register_container_instance(
|
||||
|
@ -2102,10 +2102,10 @@ class S3Response(BaseResponse):
|
||||
ps = minidom.parseString(body).getElementsByTagName("Part")
|
||||
prev = 0
|
||||
for p in ps:
|
||||
pn = int(p.getElementsByTagName("PartNumber")[0].firstChild.wholeText)
|
||||
pn = int(p.getElementsByTagName("PartNumber")[0].firstChild.wholeText) # type: ignore[union-attr]
|
||||
if pn <= prev:
|
||||
raise InvalidPartOrder()
|
||||
yield (pn, p.getElementsByTagName("ETag")[0].firstChild.wholeText)
|
||||
yield (pn, p.getElementsByTagName("ETag")[0].firstChild.wholeText) # type: ignore[union-attr]
|
||||
|
||||
def _key_response_post(
|
||||
self,
|
||||
|
@ -589,7 +589,7 @@ def test_create_service():
|
||||
response["service"]["desiredCount"].should.equal(2)
|
||||
len(response["service"]["events"]).should.equal(0)
|
||||
len(response["service"]["loadBalancers"]).should.equal(0)
|
||||
response["service"]["pendingCount"].should.equal(0)
|
||||
response["service"]["pendingCount"].should.equal(2)
|
||||
response["service"]["runningCount"].should.equal(0)
|
||||
response["service"]["serviceArn"].should.equal(
|
||||
f"arn:aws:ecs:us-east-1:{ACCOUNT_ID}:service/test_ecs_cluster/test_ecs_service"
|
||||
@ -604,6 +604,77 @@ def test_create_service():
|
||||
response["service"]["platformVersion"].should.equal("2")
|
||||
|
||||
|
||||
@mock_ecs
|
||||
@mock_ec2
|
||||
def test_create_running_service():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest(
|
||||
"Can't set environment variables in server mode for a single test"
|
||||
)
|
||||
running_service_count = 3
|
||||
with mock.patch.dict(
|
||||
os.environ, {"MOTO_ECS_SERVICE_RUNNING": str(running_service_count)}
|
||||
):
|
||||
client = boto3.client("ecs", region_name="us-east-1")
|
||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||
setup_ecs(client, ec2)
|
||||
|
||||
response = client.create_service(
|
||||
cluster="test_ecs_cluster",
|
||||
serviceName="test_ecs_service",
|
||||
taskDefinition="test_ecs_task",
|
||||
desiredCount=4,
|
||||
platformVersion="2",
|
||||
)
|
||||
|
||||
assert response["service"]["runningCount"] == running_service_count
|
||||
assert response["service"]["pendingCount"] == 1
|
||||
|
||||
|
||||
@mock_ecs
|
||||
@mock_ec2
|
||||
def test_create_running_service_bad_env_var():
|
||||
running_service_count = "ALSDHLHA;''"
|
||||
with mock.patch.dict(
|
||||
os.environ, {"MOTO_ECS_SERVICE_RUNNING": str(running_service_count)}
|
||||
):
|
||||
client = boto3.client("ecs", region_name="us-east-1")
|
||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||
setup_ecs(client, ec2)
|
||||
|
||||
response = client.create_service(
|
||||
cluster="test_ecs_cluster",
|
||||
serviceName="test_ecs_service",
|
||||
taskDefinition="test_ecs_task",
|
||||
desiredCount=2,
|
||||
platformVersion="2",
|
||||
)
|
||||
|
||||
assert response["service"]["runningCount"] == 0
|
||||
|
||||
|
||||
@mock_ecs
|
||||
@mock_ec2
|
||||
def test_create_running_service_negative_env_var():
|
||||
running_service_count = "-20"
|
||||
with mock.patch.dict(
|
||||
os.environ, {"MOTO_ECS_SERVICE_RUNNING": str(running_service_count)}
|
||||
):
|
||||
client = boto3.client("ecs", region_name="us-east-1")
|
||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||
setup_ecs(client, ec2)
|
||||
|
||||
response = client.create_service(
|
||||
cluster="test_ecs_cluster",
|
||||
serviceName="test_ecs_service",
|
||||
taskDefinition="test_ecs_task",
|
||||
desiredCount=2,
|
||||
platformVersion="2",
|
||||
)
|
||||
|
||||
assert response["service"]["runningCount"] == 0
|
||||
|
||||
|
||||
@mock_ecs
|
||||
def test_create_service_errors():
|
||||
# given
|
||||
@ -680,7 +751,7 @@ def test_create_service_scheduling_strategy():
|
||||
response["service"]["desiredCount"].should.equal(2)
|
||||
len(response["service"]["events"]).should.equal(0)
|
||||
len(response["service"]["loadBalancers"]).should.equal(0)
|
||||
response["service"]["pendingCount"].should.equal(0)
|
||||
response["service"]["pendingCount"].should.equal(2)
|
||||
response["service"]["runningCount"].should.equal(0)
|
||||
response["service"]["serviceArn"].should.equal(
|
||||
f"arn:aws:ecs:us-east-1:{ACCOUNT_ID}:service/test_ecs_cluster/test_ecs_service"
|
||||
@ -870,7 +941,9 @@ def test_describe_services():
|
||||
@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"})
|
||||
def test_describe_services_new_arn():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Cant set environment variables in server mode")
|
||||
raise SkipTest(
|
||||
"Can't set environment variables in server mode for a single test"
|
||||
)
|
||||
client = boto3.client("ecs", region_name="us-east-1")
|
||||
_ = client.create_cluster(clusterName="test_ecs_cluster")
|
||||
_ = client.register_task_definition(
|
||||
@ -1338,7 +1411,9 @@ def test_register_container_instance():
|
||||
@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"})
|
||||
def test_register_container_instance_new_arn_format():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Cant set environment variables in server mode")
|
||||
raise SkipTest(
|
||||
"Can't set environment variables in server mode for a single test"
|
||||
)
|
||||
ecs_client = boto3.client("ecs", region_name="us-east-1")
|
||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||
|
||||
@ -1876,7 +1951,9 @@ def test_run_task_default_cluster():
|
||||
@mock.patch.dict(os.environ, {"MOTO_ECS_NEW_ARN": "TrUe"})
|
||||
def test_run_task_default_cluster_new_arn_format():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Cant set environment variables in server mode")
|
||||
raise SkipTest(
|
||||
"Can't set environment variables in server mode for a single test"
|
||||
)
|
||||
client = boto3.client("ecs", region_name="us-east-1")
|
||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
||||
|
||||
@ -2953,7 +3030,7 @@ def test_create_service_load_balancing():
|
||||
"test_container_name"
|
||||
)
|
||||
response["service"]["loadBalancers"][0]["containerPort"].should.equal(123)
|
||||
response["service"]["pendingCount"].should.equal(0)
|
||||
response["service"]["pendingCount"].should.equal(2)
|
||||
response["service"]["runningCount"].should.equal(0)
|
||||
response["service"]["serviceArn"].should.equal(
|
||||
f"arn:aws:ecs:us-east-1:{ACCOUNT_ID}:service/test_ecs_cluster/test_ecs_service"
|
||||
|
Loading…
Reference in New Issue
Block a user