from ._base_response import EC2BaseResponse
class Fleets(EC2BaseResponse):
def delete_fleets(self) -> str:
fleet_ids = self._get_multi_param("FleetId.")
terminate_instances = self._get_bool_param("TerminateInstances")
fleets = self.ec2_backend.delete_fleets(fleet_ids, terminate_instances)
template = self.response_template(DELETE_FLEETS_TEMPLATE)
return template.render(fleets=fleets)
def describe_fleet_instances(self) -> str:
fleet_id = self._get_param("FleetId")
instances = self.ec2_backend.describe_fleet_instances(fleet_id)
template = self.response_template(DESCRIBE_FLEET_INSTANCES_TEMPLATE)
return template.render(fleet_id=fleet_id, instances=instances)
def describe_fleets(self) -> str:
fleet_ids = self._get_multi_param("FleetId.")
requests = self.ec2_backend.describe_fleets(fleet_ids)
template = self.response_template(DESCRIBE_FLEETS_TEMPLATE)
rend = template.render(requests=requests)
return rend
def create_fleet(self) -> str:
on_demand_options = self._get_multi_param_dict("OnDemandOptions")
spot_options = self._get_multi_param_dict("SpotOptions")
target_capacity_specification = self._get_multi_param_dict(
"TargetCapacitySpecification"
)
launch_template_configs = self._get_multi_param(
param_prefix="LaunchTemplateConfigs"
)
# Our multi_param function doesn't understand when to return a list, a string, or a dictionary
# So we'll have to help it a little, by explicitly asking for a dict if we're getting anything else back
for idx, config in enumerate(launch_template_configs, start=1):
if (overrides := config.get("Overrides")) and not isinstance(
overrides, dict
):
config["Overrides"] = self._get_multi_param(
f"LaunchTemplateConfigs.{idx}.Overrides",
skip_result_conversion=True,
)
if (spec := config.get("LaunchTemplateSpecification")) and not isinstance(
spec, dict
):
config["LaunchTemplateSpecification"] = self._get_multi_param_dict(
f"LaunchTemplateConfigs.{idx}.LaunchTemplateSpecification"
)
excess_capacity_termination_policy = self._get_param(
"ExcessCapacityTerminationPolicy"
)
replace_unhealthy_instances = self._get_param("ReplaceUnhealthyInstances")
terminate_instances_with_expiration = self._get_param(
"TerminateInstancesWithExpiration", if_none=True
)
fleet_type = self._get_param("Type", if_none="maintain")
valid_from = self._get_param("ValidFrom")
valid_until = self._get_param("ValidUntil")
tag_specifications = self._get_multi_param("TagSpecification")
request = self.ec2_backend.create_fleet(
on_demand_options=on_demand_options,
spot_options=spot_options,
target_capacity_specification=target_capacity_specification,
launch_template_configs=launch_template_configs,
excess_capacity_termination_policy=excess_capacity_termination_policy,
replace_unhealthy_instances=replace_unhealthy_instances,
terminate_instances_with_expiration=terminate_instances_with_expiration,
fleet_type=fleet_type,
valid_from=valid_from,
valid_until=valid_until,
tag_specifications=tag_specifications,
)
template = self.response_template(CREATE_FLEET_TEMPLATE)
return template.render(request=request)
CREATE_FLEET_TEMPLATE = """<CreateFleetResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>60262cc5-2bd4-4c8d-98ed-example</requestId>
<fleetId>{{ request.id }}</fleetId>
{% if request.fleet_type == "instant" %}
<fleetInstanceSet>
{% for instance in request.on_demand_instances %}
<item>
<instanceType>{{ instance["instance"].instance_type }}</instanceType>
<lifecycle>on-demand</lifecycle>
<instanceIds>
<item>{{ instance["instance"].id }}</item>
</instanceIds>
</item>
{% endfor %}
{% for instance in request.spot_requests %}
<item>
<instanceType>{{ instance.instance.instance_type }}</instanceType>
<lifecycle>spot</lifecycle>
<instanceIds>
<item>{{ instance.instance.id }}</item>
</instanceIds>
</item>
{% endfor %}
</fleetInstanceSet>
{% endif %}
</CreateFleetResponse>"""
DESCRIBE_FLEETS_TEMPLATE = """<DescribeFleetsResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
<requestId>4d68a6cc-8f2e-4be1-b425-example</requestId>
<fleetSet>
{% for request in requests %}
<item>
<fleetId>{{ request.id }}</fleetId>
<fleetState>{{ request.state }}</fleetState>
<excessCapacityTerminationPolicy>{{ request.excess_capacity_termination_policy }}</excessCapacityTerminationPolicy>
<fulfilledCapacity>{{ request.fulfilled_capacity }}</fulfilledCapacity>
<fulfilledOnDemandCapacity>{{ request.fulfilled_on_demand_capacity }}</fulfilledOnDemandCapacity>
<launchTemplateConfigs>
{% for config in request.launch_template_configs %}
<item>
<launchTemplateSpecification>
<launchTemplateId>{{ config.LaunchTemplateSpecification.LaunchTemplateId }}</launchTemplateId>
<version>{{ config.LaunchTemplateSpecification.Version }}</version>
</launchTemplateSpecification>
{% if config.Overrides %}
<overrides>
{% for override in config.Overrides %}
<item>
{% if override.AvailabilityZone %}
<availabilityZone>{{ override.AvailabilityZone }}</availabilityZone>
{% endif %}
{% if override.InstanceType %}
<instanceType>{{ override.InstanceType }}</instanceType>
{% endif %}
{% if override.InstanceRequirements %}
<instanceRequirements>
{% if override.InstanceRequirements.AcceleratorCount %}
<acceleratorCount>
{% if override.InstanceRequirements.AcceleratorCount.Max %}
<max>{{ override.InstanceRequirements.AcceleratorCount.Max }}</max>
{% endif %}
{% if override.InstanceRequirements.AcceleratorCount.Min %}
<min>{{ override.InstanceRequirements.AcceleratorCount.Min }}</min>
{% endif %}
</acceleratorCount>
{% endif %}
{% if override.InstanceRequirements.AcceleratorManufacturer %}
<acceleratorManufacturerSet>
{% for manufacturer in override.InstanceRequirements.AcceleratorManufacturer %}
<item>{{ manufacturer }}</item>
{% endfor %}
</acceleratorManufacturerSet>
{% endif %}
{% if override.InstanceRequirements.AcceleratorName %}
<acceleratorNameSet>
{% for name in override.InstanceRequirements.AcceleratorName %}
<item>{{ name }}</item>
{% endfor %}
</acceleratorNameSet>
{% endif %}
{% if override.InstanceRequirements.AcceleratorTotalMemoryMiB %}
<acceleratorTotalMemoryMiB>
{% if override.InstanceRequirements.AcceleratorTotalMemoryMiB.Max %}
<max>{{ override.InstanceRequirements.AcceleratorTotalMemoryMiB.Max }}</max>
{% endif %}
{% if override.InstanceRequirements.AcceleratorTotalMemoryMiB.Min %}
<min>{{ override.InstanceRequirements.AcceleratorTotalMemoryMiB.Min }}</min>
{% endif %}
</acceleratorTotalMemoryMiB>
{% endif %}
{% if override.InstanceRequirements.AcceleratorType %}
<acceleratorTypeSet>
{% for type in override.InstanceRequirements.AcceleratorType %}
<item>{{ type }}</item>
{% endfor %}
</acceleratorTypeSet>
{% endif %}
{% if override.InstanceRequirements.BareMetal %}
<bareMetal>{{ override.InstanceRequirements.BareMetal }}</bareMetal>
{% endif %}
{% if override.InstanceRequirements.BaselineEbsBandwidthMbps %}
<baselineEbsBandwidthMbps>
{% if override.InstanceRequirements.BaselineEbsBandwidthMbps.Min %}
<min>{{ override.InstanceRequirements.BaselineEbsBandwidthMbps.Min }}</min>
{% endif %}
{% if override.InstanceRequirements.BaselineEbsBandwidthMbps.Max %}
<max>{{ override.InstanceRequirements.BaselineEbsBandwidthMbps.Max }}</max>
{% endif %}
</baselineEbsBandwidthMbps>
{% endif %}
{% if override.InstanceRequirements.BurstablePerformance %}
<burstablePerformance>{{ override.InstanceRequirements.BurstablePerformance }}</burstablePerformance>
{% endif %}
{% if override.InstanceRequirements.CpuManufacturer %}
<cpuManufacturerSet>
{% for manufacturer in override.InstanceRequirements.CpuManufacturer %}
<item>{{ manufacturer }}</item>
{% endfor %}
</cpuManufacturerSet>
{% endif %}
{% if override.InstanceRequirements.ExcludedInstanceType %}
<excludedInstanceTypeSet>
{% for type in override.InstanceRequirements.ExcludedInstanceType %}
<item>{{ type }}</item>
{% endfor %}
</excludedInstanceTypeSet>
{% endif %}
{% if override.InstanceRequirements.InstanceGeneration %}
<instanceGenerationSet>
{% for generation in override.InstanceRequirements.InstanceGeneration %}
<item>{{ generation }}</item>
{% endfor %}
</instanceGenerationSet>
{% endif %}
{% if override.InstanceRequirements.LocalStorage %}
<localStorage>{{ override.InstanceRequirements.LocalStorage }}</localStorage>
{% endif %}
{% if override.InstanceRequirements.LocalStorageType %}
<localStorageTypeSet>
{% for type in override.InstanceRequirements.LocalStorageType %}
<item>{{ type }}</item>
{% endfor %}
</localStorageTypeSet>
{% endif %}
{% if override.InstanceRequirements.MemoryGiBPerVCpu %}
<memoryGiBPerVCpu>
{% if override.InstanceRequirements.MemoryGiBPerVCpu.Min %}
<min>{{ override.InstanceRequirements.MemoryGiBPerVCpu.Min }}</min>
{% endif %}
{% if override.InstanceRequirements.MemoryGiBPerVCpu.Max %}
<max>{{ override.InstanceRequirements.MemoryGiBPerVCpu.Max }}</max>
{% endif %}
</memoryGiBPerVCpu>
{% endif %}
{% if override.InstanceRequirements.MemoryMiB %}
<memoryMiB>
{% if override.InstanceRequirements.MemoryMiB.Min %}
<min>{{ override.InstanceRequirements.MemoryMiB.Min }}</min>
{% endif %}
{% if override.InstanceRequirements.MemoryMiB.Max %}
<max>{{ override.InstanceRequirements.MemoryMiB.Max }}</max>
{% endif %}
</memoryMiB>
{% endif %}
{% if override.InstanceRequirements.NetworkInterfaceCount %}
<networkInterfaceCount>
{% if override.InstanceRequirements.NetworkInterfaceCount.Max %}
<max>{{ override.InstanceRequirements.NetworkInterfaceCount.Max }}</max>
{% endif %}
{% if override.InstanceRequirements.NetworkInterfaceCount.Min %}
<min>{{ override.InstanceRequirements.NetworkInterfaceCount.Min }}</min>
{% endif %}
</networkInterfaceCount>
{% endif %}
{% if override.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice %}
<onDemandMaxPricePercentageOverLowestPrice>{{ override.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice }}</onDemandMaxPricePercentageOverLowestPrice>
{% endif %}
{% if override.InstanceRequirements.RequireHibernateSupport %}
<requireHibernateSupport>{{ override.InstanceRequirements.RequireHibernateSupport }}</requireHibernateSupport>
{% endif %}
{% if override.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice %}
<spotMaxPricePercentageOverLowestPrice>{{ override.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice }}</spotMaxPricePercentageOverLowestPrice>
{% endif %}
{% if override.InstanceRequirements.TotalLocalStorageGB %}
<totalLocalStorageGB>
{% if override.InstanceRequirements.TotalLocalStorageGB.Min %}
<min>{{ override.InstanceRequirements.TotalLocalStorageGB.Min }}</min>
{% endif %}
{% if override.InstanceRequirements.TotalLocalStorageGB.Max %}
<max>{{ override.InstanceRequirements.TotalLocalStorageGB.Max }}</max>
{% endif %}
</totalLocalStorageGB>
{% endif %}
{% if override.InstanceRequirements.VCpuCount %}
<vCpuCount>
{% if override.InstanceRequirements.VCpuCount.Min %}
<min>{{ override.InstanceRequirements.VCpuCount.Min }}</min>
{% endif %}
{% if override.InstanceRequirements.VCpuCount.Max %}
<max>{{ override.InstanceRequirements.VCpuCount.Max }}</max>
{% endif %}
</vCpuCount>
{% endif %}
</instanceRequirements>
{% endif %}
{% if override.MaxPrice %}
<maxPrice>{{ override.MaxPrice }}</maxPrice>
{% endif %}
{% if override.Placement %}
<placement>
{% if override.Placement.GroupName %}
<groupName>{{ override.Placement.GroupName }}</groupName>
{% endif %}
</placement>
{% endif %}
{% if override.Priority %}
<priority>{{ override.Priority }}</priority>
{% endif %}
{% if override.SubnetId %}
<subnetId>{{ override.SubnetId }}</subnetId>
{% endif %}
{% if override.WeightedCapacity %}
<weightedCapacity>{{ override.WeightedCapacity }}</weightedCapacity>
{% endif %}
</item>
{% endfor %}
</overrides>
{% endif %}
</item>
{% endfor %}
</launchTemplateConfigs>
<targetCapacitySpecification>
<totalTargetCapacity>{{ request.target_capacity }}</totalTargetCapacity>
{% if request.on_demand_target_capacity %}
<onDemandTargetCapacity>{{ request.on_demand_target_capacity }}</onDemandTargetCapacity>
{% endif %}
{% if request.spot_target_capacity %}
<spotTargetCapacity>{{ request.spot_target_capacity }}</spotTargetCapacity>
{% endif %}
<defaultTargetCapacityType>{{ request.target_capacity_specification.DefaultTargetCapacityType }}</defaultTargetCapacityType>
</targetCapacitySpecification>
{% if request.spot_options %}
<spotOptions>
{% if request.spot_options.AllocationStrategy %}
<allocationStrategy>{{ request.spot_options.AllocationStrategy }}</allocationStrategy>
{% endif %}
{% if request.spot_options.InstanceInterruptionBehavior %}
<instanceInterruptionBehavior>{{ request.spot_options.InstanceInterruptionBehavior }}</instanceInterruptionBehavior>
{% endif %}
{% if request.spot_options.InstancePoolsToUseCount %}
<instancePoolsToUseCount>{{ request.spot_options.InstancePoolsToUseCount }}</instancePoolsToUseCount>
{% endif %}
{% if request.spot_options.MaintenanceStrategies %}
<maintenanceStrategies>
{% if request.spot_options.MaintenanceStrategies.CapacityRebalance %}
<capacityRebalance>
{% if request.spot_options.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy %}
<replacementStrategy>{{ request.spot_options.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy }}</replacementStrategy>
{% endif %}
{% if request.spot_options.MaintenanceStrategies.CapacityRebalance.TerminationDelay %}
<terminationDelay>{{ request.spot_options.MaintenanceStrategies.CapacityRebalance.TerminationDelay }}</terminationDelay>
{% endif %}
</capacityRebalance>
{% endif %}
</maintenanceStrategies>
{% endif %}
{% if request.spot_options.MaxTotalPrice %}
<maxTotalPrice>{{ request.spot_options.MaxTotalPrice }}</maxTotalPrice>
{% endif %}
{% if request.spot_options.MinTargetCapacity %}
<minTargetCapacity>{{ request.spot_options.MinTargetCapacity }}</minTargetCapacity>
{% endif %}
{% if request.spot_options.SingleAvailabilityZone %}
<singleAvailabilityZone>{{ request.spot_options.SingleAvailabilityZone }}</singleAvailabilityZone>
{% endif %}
{% if request.spot_options.SingleInstanceType %}
<singleInstanceType>{{ request.spot_options.SingleInstanceType }}</singleInstanceType>
{% endif %}
</spotOptions>
{% endif %}
<!-- {'AllocationStrategy': 'lowest-price', 'MaxTotalPrice': '50', 'MinTargetCapacity': 1, 'SingleAvailabilityZone': True, 'SingleInstanceType': True} -->
{% if request.on_demand_options %}
<onDemandOptions>
{% if request.on_demand_options.AllocationStrategy %}
<allocationStrategy>{{ request.on_demand_options.AllocationStrategy }}</allocationStrategy>
{% endif %}
{% if request.on_demand_options.MaxTotalPrice %}
<maxTotalPrice>{{ request.on_demand_options.MaxTotalPrice }}</maxTotalPrice>
{% endif %}
{% if request.on_demand_options.MinTargetCapacity %}
<minTargetCapacity>{{ request.on_demand_options.MinTargetCapacity }}</minTargetCapacity>
{% endif %}
{% if request.on_demand_options.SingleAvailabilityZone %}
<singleAvailabilityZone>{{ request.on_demand_options.SingleAvailabilityZone }}</singleAvailabilityZone>
{% endif %}
{% if request.on_demand_options.SingleInstanceType %}
<singleInstanceType>{{ request.on_demand_options.SingleInstanceType }}</singleInstanceType>
{% endif %}
{% if request.on_demand_options.CapacityReservationOptions %}
<capacityReservationOptions>
{% if request.on_demand_options.CapacityReservationOptions.UsageStrategy %}
<usageStrategy>{{ request.on_demand_options.CapacityReservationOptions.UsageStrategy }}</usageStrategy>
{% endif %}
</capacityReservationOptions>
{% endif %}
</onDemandOptions>
{% endif %}
<terminateInstancesWithExpiration>{{ request.terminate_instances_with_expiration }}</terminateInstancesWithExpiration>
<type>{{ request.fleet_type }}</type>
{% if request.valid_from %}
<validFrom>{{ request.valid_from }}</validFrom>
{% endif %}
{% if request.valid_until %}
<validUntil>{{ request.valid_until }}</validUntil>
{% endif %}
<replaceUnhealthyInstances>{{ request.replace_unhealthy_instances }}</replaceUnhealthyInstances>
<tagSet>
{% for tag in request.tags %}
<item>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
</item>
{% endfor %}
</fleetSet>
</DescribeFleetsResponse>"""
DESCRIBE_FLEET_INSTANCES_TEMPLATE = """<DescribeFleetInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
<requestId>cfb09950-45e2-472d-a6a9-example</requestId>
<fleetId>{{ fleet_id }}</fleetId>
<activeInstanceSet>
{% for i in instances %}
<item>
<instanceId>{{ i.instance.id }}</instanceId>
{% if i.id %}
<spotInstanceRequestId>{{ i.id }}</spotInstanceRequestId>
{% endif %}
<instanceType>{{ i.instance.instance_type }}</instanceType>
<instanceHealth>healthy</instanceHealth>
</item>
{% endfor %}
</activeInstanceSet>
</DescribeFleetInstancesResponse>
"""
DELETE_FLEETS_TEMPLATE = """<DeleteFleetResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
<requestId>e12d2fe5-6503-4b4b-911c-example</requestId>
<unsuccessfulFleetDeletionSet/>
<successfulFleetDeletionSet>
{% for fleet in fleets %}
<item>
<fleetId>{{ fleet.id }}</fleetId>
<currentFleetState>{{ fleet.state }}</currentFleetState>
<previousFleetState>active</previousFleetState>
</item>
{% endfor %}
</successfulFleetDeletionSet>
</DeleteFleetResponse>"""