EC2: delete_fleet() should set correct status (#6863)

This commit is contained in:
Bert Blommers 2023-09-29 12:07:38 +00:00 committed by GitHub
parent 438b2b7843
commit 5563e62f21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 48 deletions

View File

@ -42,4 +42,4 @@ jobs:
env: env:
MOTO_TEST_ALLOW_AWS_REQUEST: ${{ true }} MOTO_TEST_ALLOW_AWS_REQUEST: ${{ true }}
run: | run: |
pytest -sv tests/test_s3 -m aws_verified pytest -sv tests/test_ec2/ tests/test_s3 -m aws_verified

View File

@ -308,12 +308,19 @@ class FleetsBackend:
def delete_fleets( def delete_fleets(
self, fleet_ids: List[str], terminate_instances: bool self, fleet_ids: List[str], terminate_instances: bool
) -> List[Fleet]: ) -> List[Fleet]:
fleets = [] fleets = []
for fleet_id in fleet_ids: for fleet_id in fleet_ids:
fleet = self.fleets[fleet_id] fleet = self.fleets[fleet_id]
if terminate_instances: if terminate_instances:
# State indicates the fleet is in the process of being terminated
# AWS will change the state to `deleted` after a few seconds/minutes
# Note that it will stay in the `deleted`-state for at least a few hours
fleet.state = "deleted_terminating"
fleet.target_capacity = 0 fleet.target_capacity = 0
fleet.terminate_instances() fleet.terminate_instances()
else:
# State is different, and indicates that instances are still running
fleet.state = "deleted_running"
fleets.append(fleet) fleets.append(fleet)
fleet.state = "deleted"
return fleets return fleets

View File

@ -4,7 +4,7 @@ from ._base_response import EC2BaseResponse
class Fleets(EC2BaseResponse): class Fleets(EC2BaseResponse):
def delete_fleets(self) -> str: def delete_fleets(self) -> str:
fleet_ids = self._get_multi_param("FleetId.") fleet_ids = self._get_multi_param("FleetId.")
terminate_instances = self._get_param("TerminateInstances") terminate_instances = self._get_bool_param("TerminateInstances")
fleets = self.ec2_backend.delete_fleets(fleet_ids, terminate_instances) fleets = self.ec2_backend.delete_fleets(fleet_ids, terminate_instances)
template = self.response_template(DELETE_FLEETS_TEMPLATE) template = self.response_template(DELETE_FLEETS_TEMPLATE)
return template.render(fleets=fleets) return template.render(fleets=fleets)

View File

@ -0,0 +1,33 @@
import os
from functools import wraps
from moto import mock_ec2, mock_ssm
def ec2_aws_verified(func):
"""
Function that is verified to work against AWS.
Can be run against AWS at any time by setting:
MOTO_TEST_ALLOW_AWS_REQUEST=true
If this environment variable is not set, the function runs in a `mock_s3` context.
This decorator will:
- Create a bucket
- Run the test and pass the bucket_name as an argument
- Delete the objects and the bucket itself
"""
@wraps(func)
def pagination_wrapper():
allow_aws = (
os.environ.get("MOTO_TEST_ALLOW_AWS_REQUEST", "false").lower() == "true"
)
if allow_aws:
resp = func()
else:
with mock_ec2(), mock_ssm():
resp = func()
return resp
return pagination_wrapper

View File

@ -5,6 +5,8 @@ from moto import mock_ec2
from tests import EXAMPLE_AMI_ID from tests import EXAMPLE_AMI_ID
from uuid import uuid4 from uuid import uuid4
from . import ec2_aws_verified
def get_subnet_id(conn): def get_subnet_id(conn):
vpc = conn.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"] vpc = conn.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]
@ -15,11 +17,11 @@ def get_subnet_id(conn):
return subnet_id return subnet_id
def get_launch_template(conn, instance_type="t2.micro"): def get_launch_template(conn, instance_type="t2.micro", ami_id=EXAMPLE_AMI_ID):
launch_template = conn.create_launch_template( launch_template = conn.create_launch_template(
LaunchTemplateName="test" + str(uuid4()), LaunchTemplateName="test" + str(uuid4()),
LaunchTemplateData={ LaunchTemplateData={
"ImageId": EXAMPLE_AMI_ID, "ImageId": ami_id,
"InstanceType": instance_type, "InstanceType": instance_type,
"KeyName": "test", "KeyName": "test",
"SecurityGroups": ["sg-123456"], "SecurityGroups": ["sg-123456"],
@ -40,6 +42,29 @@ def get_launch_template(conn, instance_type="t2.micro"):
return launch_template_id, launch_template_name return launch_template_id, launch_template_name
class launch_template_context:
def __init__(self, region: str = "us-west-2"):
self.ec2 = boto3.client("ec2", region_name=region)
self.ssm = boto3.client("ssm", region_name=region)
def __enter__(self):
kernel_61 = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64"
ami_id = self.ssm.get_parameter(Name=kernel_61)["Parameter"]["Value"]
self.lt_id, self.lt_name = get_launch_template(self.ec2, ami_id=ami_id)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.ec2.delete_launch_template(LaunchTemplateId=self.lt_id)
@ec2_aws_verified
def test_launch_template_is_created_properly():
with launch_template_context() as ctxt:
template = ctxt.ec2.describe_launch_templates()["LaunchTemplates"][0]
assert template["DefaultVersionNumber"] == 1
assert template["LatestVersionNumber"] == 1
@mock_ec2 @mock_ec2
def test_create_spot_fleet_with_lowest_price(): def test_create_spot_fleet_with_lowest_price():
conn = boto3.client("ec2", region_name="us-west-2") conn = boto3.client("ec2", region_name="us-west-2")
@ -354,61 +379,66 @@ def test_create_fleet_using_launch_template_config__overrides():
assert instance["SubnetId"] == subnet_id assert instance["SubnetId"] == subnet_id
@mock_ec2 @ec2_aws_verified
def test_delete_fleet(): def test_delete_fleet():
conn = boto3.client("ec2", region_name="us-west-2") with launch_template_context() as ctxt:
launch_template_id, _ = get_launch_template(conn) fleet_res = ctxt.ec2.create_fleet(
LaunchTemplateConfigs=[
fleet_res = conn.create_fleet( {
LaunchTemplateConfigs=[ "LaunchTemplateSpecification": {
{ "LaunchTemplateId": ctxt.lt_id,
"LaunchTemplateSpecification": { "Version": "1",
"LaunchTemplateId": launch_template_id, },
"Version": "1",
}, },
],
TargetCapacitySpecification={
"DefaultTargetCapacityType": "spot",
"OnDemandTargetCapacity": 1,
"SpotTargetCapacity": 2,
"TotalTargetCapacity": 3,
}, },
], SpotOptions={
TargetCapacitySpecification={ "AllocationStrategy": "lowestPrice",
"DefaultTargetCapacityType": "spot", "InstanceInterruptionBehavior": "terminate",
"OnDemandTargetCapacity": 1, },
"SpotTargetCapacity": 2, Type="maintain",
"TotalTargetCapacity": 3, )
}, fleet_id = fleet_res["FleetId"]
SpotOptions={
"AllocationStrategy": "lowestPrice",
"InstanceInterruptionBehavior": "terminate",
},
Type="maintain",
ValidFrom="2020-01-01T00:00:00Z",
ValidUntil="2020-12-31T00:00:00Z",
)
fleet_id = fleet_res["FleetId"]
delete_fleet_out = conn.delete_fleets(FleetIds=[fleet_id], TerminateInstances=True) successfull_deletions = ctxt.ec2.delete_fleets(
FleetIds=[fleet_id], TerminateInstances=False
)["SuccessfulFleetDeletions"]
assert len(delete_fleet_out["SuccessfulFleetDeletions"]) == 1 assert len(successfull_deletions) == 1
assert delete_fleet_out["SuccessfulFleetDeletions"][0]["FleetId"] == fleet_id assert successfull_deletions[0]["FleetId"] == fleet_id
assert ( assert successfull_deletions[0]["CurrentFleetState"] == "deleted_running"
delete_fleet_out["SuccessfulFleetDeletions"][0]["CurrentFleetState"]
== "deleted"
)
fleets = conn.describe_fleets(FleetIds=[fleet_id])["Fleets"] successfull_deletions = ctxt.ec2.delete_fleets(
assert len(fleets) == 1 FleetIds=[fleet_id], TerminateInstances=True
)["SuccessfulFleetDeletions"]
target_capacity_specification = fleets[0]["TargetCapacitySpecification"] assert len(successfull_deletions) == 1
assert target_capacity_specification["TotalTargetCapacity"] == 0 assert successfull_deletions[0]["FleetId"] == fleet_id
assert fleets[0]["FleetState"] == "deleted" assert successfull_deletions[0]["CurrentFleetState"] == "deleted_terminating"
# Instances should be terminated fleets = ctxt.ec2.describe_fleets(FleetIds=[fleet_id])["Fleets"]
instance_res = conn.describe_fleet_instances(FleetId=fleet_id) assert len(fleets) == 1
instances = instance_res["ActiveInstances"]
assert len(instances) == 0 # AWS doesn't reset this, but Moto does
# we should figure out why Moto sets this value to 0
# target_capacity_specification = fleets[0]["TargetCapacitySpecification"]
# assert target_capacity_specification["TotalTargetCapacity"] == 3
assert fleets[0]["FleetState"] == "deleted_terminating"
# Instances should be terminated
instance_res = ctxt.ec2.describe_fleet_instances(FleetId=fleet_id)
instances = instance_res["ActiveInstances"]
assert len(instances) == 0
@mock_ec2 @mock_ec2
def test_describe_fleet_instences_api(): def test_describe_fleet_instances_api():
conn = boto3.client("ec2", region_name="us-west-1") conn = boto3.client("ec2", region_name="us-west-1")
launch_template_id, _ = get_launch_template(conn) launch_template_id, _ = get_launch_template(conn)