EC2: delete_fleet() should set correct status (#6863)
This commit is contained in:
parent
438b2b7843
commit
5563e62f21
2
.github/workflows/tests_real_aws.yml
vendored
2
.github/workflows/tests_real_aws.yml
vendored
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user