Auto Scaling
Floci implements the EC2 Auto Scaling API — stored-state management for launch configurations, auto scaling groups, lifecycle hooks, and scaling policies, plus a real capacity reconciler that launches and terminates EC2 instances to maintain desired capacity.
Protocol: Query — POST / with Action= form parameter, credential scope autoscaling
XML namespace: http://autoscaling.amazonaws.com/doc/2011-01-01/, as declared by the AWS service model.
ARN formats:
arn:aws:autoscaling:<region>:<account>:autoScalingGroup:<uuid>:autoScalingGroupName/<name>arn:aws:autoscaling:<region>:<account>:launchConfiguration:<uuid>:launchConfigurationName/<name>arn:aws:autoscaling:<region>:<account>:scalingPolicy:<uuid>:autoScalingGroupName/<group>/policyName/<name>
Supported Operations (55 total)
Launch Configurations
| Operation | Notes |
|---|---|
CreateLaunchConfiguration |
Stores template: ImageId, InstanceType, KeyName, SecurityGroups, UserData, IamInstanceProfile, InstanceMonitoring, BlockDeviceMappings, MetadataOptions |
DescribeLaunchConfigurations |
Filtered by name list; returns all if no filter |
DeleteLaunchConfiguration |
Removes the named launch configuration |
Auto Scaling Groups
| Operation | Notes |
|---|---|
CreateAutoScalingGroup |
Creates a group with min/max/desired capacity, AZs, tags, launch configuration, launch template, or mixed instances policy; starts capacity reconciliation loop |
DescribeAutoScalingGroups |
Filtered by name list; returns all if no filter; includes current instance list with lifecycle state and mixed instances policy shape when configured |
UpdateAutoScalingGroup |
Updates capacity bounds, cooldown, launch source, AZs |
DeleteAutoScalingGroup |
ForceDelete=true terminates all instances before deletion |
DescribeTags |
Group tags; filters auto-scaling-group, key, value, propagate-at-launch (values ORed, filters ANDed); MaxRecords/NextToken paging |
CreateOrUpdateTags |
Creates or updates group tags and their propagate-at-launch setting |
DeleteTags |
Removes named group tags |
EnableMetricsCollection |
Records the named group metrics, or all 20 when none are named, as EnabledMetrics on DescribeAutoScalingGroups. Granularity is required and must be 1Minute; an unknown metric name raises ValidationError. No metrics are published to CloudWatch |
DisableMetricsCollection |
Removes the named metrics from EnabledMetrics, or all of them when none are named |
CreateAutoScalingGroup accepts both subnet-a,subnet-b and
subnet-a, subnet-b in VPCZoneIdentifier. DescribeAutoScalingGroups returns the
comma-only form. This matches a live AWS comparison in us-east-1 on October 12,
2026 at 17:30 UTC: two subnets, matching Availability Zones, one launch template
and zero capacity. Both groups had identical configuration except for name, ARN
and creation time. The SDK regression is
compatibility-tests/sdk-test-python/tests/test_autoscaling_subnet_whitespace.py.
Capacity reservation targets remain limited to one reservation ID or one resource
group ARN. Multiple entries, including duplicates, return ValidationError;
mixing IDs and group ARNs returns a distinct validation message. These messages
match live AWS comparisons on November 2, 2026 in us-east-1 and eu-west-1
for create, and eu-west-1 for update, using zero desired capacity.
Rejected updates preserve the group's existing configuration. This does not
enable preview support for multiple reservation targets.
When AvailabilityZones is omitted, group creation and subnet updates derive the
distinct zones from VPCZoneIdentifier. Updates without placement fields retain
the group's current subnet and zone selection. Zone derivation rejects missing
subnet IDs with ValidationError before changing an existing group or storing a
new one.
Scale-out follows the AWS placement rules: choose the zone with the fewest active instances, then its subnet with the most free IPv4 addresses. Declared subnets and actual EC2 placement take precedence over stale group zone metadata. Exhausted IPv4 subnets are skipped when another subnet has capacity. If all are full, EC2 reports the selected subnet's allocation error. IPv6-only subnets do not require free IPv4 addresses. Retrying another zone after a launch error and rebalancing without a capacity increase are not implemented.
AWS launch errors appear as failed scaling activities after preserving partial
launches. Repeated identical failures reuse the recorded activity, following the
scale-in behavior, and do not complete an instance refresh. Unexpected runtime
failures in ordinary scale-out, and save and cleanup failures, still propagate.
Refresh launch failures retain the original replacement attempt and appear as
failed scaling activities while other replacements can continue. Refresh and
ordinary launches share the same launch settings, including the block device mappings
of the launch template or launch configuration; accepted refresh launches keep their
recorded source identity. A launch template or launch configuration a CloudFormation
stack creates carries no block device mappings yet, so its instances get the AMI's
devices alone. CreateLaunchConfiguration refuses a block device mapping without a
DeviceName, or with a Boolean or integer member it cannot parse, and stores the rest as
given; the mappings are otherwise checked only when a group launches from the
configuration, by the checks RunInstances applies. Neither step applies the ranges the
Auto Scaling model sets for VolumeSize, Iops and Throughput, and the volume types a
launch accepts are EC2's, io2 included. A mapping EC2 refuses, such as an invalid device
name or a snapshot that does not exist, fails that launch and is recorded as a failed
scaling activity.
An EBS mapping supplied by a launch configuration defaults DeleteOnTermination to
true, even when the AMI's mapping sets it to false. An explicit false in the
launch configuration keeps the volume after termination.
For groups configured only with Availability Zones, Floci preserves its unpinned
EC2 launch behavior and counts each member under the requested zone. This permits
real zones outside the local subnet catalog, such as us-east-1d; the underlying
EC2 instance can use a default subnet in a different zone.
Instance Management
| Operation | Notes |
|---|---|
DescribeAutoScalingInstances |
Returns all ASG-tracked instances with their group name, lifecycle state and health status. Health is in capitals here: HEALTHY, as the AWS samples show, and UNHEALTHY by the same rule. DescribeAutoScalingGroups reports Healthy or Unhealthy |
SetInstanceHealth |
Updates an instance's health status immediately; accepts but does not enforce the grace-period flag |
SetInstanceProtection |
Enables or disables scale-in protection for named instances in a group |
SetDesiredCapacity |
Updates desired count; reconciler handles scale-out / scale-in within 10 s |
AttachInstances |
Attaches existing EC2 instances to a group; sets lifecycle state to InService. Refuses the whole batch with ValidationError when an instance already belongs to a group |
DetachInstances |
Detaches instances from a group; optionally decrements desired capacity |
TerminateInstanceInAutoScalingGroup |
Terminates a specific instance; optionally decrements desired capacity |
EnterStandby |
Moves InService instances to EnteringStandby and returns one InProgress activity (progress 50) per instance; the reconciler deregisters them from the group's target groups and Classic Load Balancers and sets Standby within 10 s. ShouldDecrementDesiredCapacity=true lowers desired capacity by the number of instances, refused with ValidationError below MinSize; false keeps it, so the group launches replacements |
ExitStandby |
Moves Standby instances to Pending, raises desired capacity by the number of instances (refused with ValidationError above MaxSize) and returns one PreInService activity (progress 30) per instance; the reconciler registers them with the group's load balancers and sets InService within 10 s |
SuspendProcesses |
Records suspended scaling processes (empty list suspends all); reported back by DescribeAutoScalingGroups |
ResumeProcesses |
Clears suspended processes (empty list resumes all) |
CreateAutoScalingGroup defaults an omitted tag PropagateAtLaunch to true;
an explicit false keeps that tag on the group. CreateOrUpdateTags requires the
flag on every tag, including existing tags. If any flag is omitted, the request
returns ValidationError before changing any tags in that batch. DeleteTags
allows the flag to be omitted.
Member instances carry the tags the
EC2 instance tagging lifecycle
describes. An instance the group launches gets its launch template's instance tags, then the
group's PropagateAtLaunch tags, which win a key both set, then aws:autoscaling:groupName with
the group's name. AttachInstances adds the same group tags and aws:autoscaling:groupName,
overwriting existing tags with the same keys. DetachInstances removes only
aws:autoscaling:groupName, and only while it names the group being detached from.
AttachInstances does not yet refuse what AWS refuses for the instance's state or zone or for
the group's MaxSize, and does not grow desired capacity by the number of instances attached.
An ID EC2 has no instance for joins the group without tags.
Standby follows the
user guide.
A member in EnteringStandby or Standby does not count toward desired capacity, including when
AttachInstances raises desired capacity to the group's size, and is never chosen for scale-in or
instance refresh. StartInstanceRefresh leaves such members alone whatever its StandbyInstances
preference says, as AWS does for Ignore; AWS's default, Wait, and Terminate are not
implemented. A member keeps its health status in standby and when it returns to service, and stays
in the group even when its EC2 instance stops or terminates. If it did, the member fails the health
check AWS runs when it exits standby: Floci terminates the instance if EC2 still has it, records
AWS's Terminating EC2 instance activity, and the group launches a replacement.
Each move's activity carries the description and cause AWS writes and completes as Successful in
DescribeScalingActivities when the instance reaches Standby or InService. It completes as
Cancelled when the instance is terminated first, fails that health check, is replaced by an
instance refresh on its way back to service, or when the group is deleted. DetachInstances refuses
an instance whose move is still in progress, such as one in EnteringStandby or Pending on its way
back, with The instance <id> is not in InService or Standby., AWS's answer for a state it does not
detach; Floci does not refuse the other such states yet. Floci does not wait for connection draining and
does not write the activity's Details member.
Instance Refresh
| Operation | Notes |
|---|---|
StartInstanceRefresh |
Starts replacement of group instances and returns a refresh ID |
DescribeInstanceRefreshes |
Returns refresh status and progress, with MaxRecords/NextToken paging |
Instance Refresh Recovery
New instance refreshes retain the selected instances and their replacement progress
across persistent, hybrid, and WAL storage reloads. Suspending InstanceRefresh,
Launch, or Terminate pauses refresh replacements; resuming those processes lets
the refresh continue. A failed replacement launch remains part of the refresh, so
ordinary desired-capacity reconciliation does not bypass the pause. Explicit
TerminateInstanceInAutoScalingGroup requests still run, and independent capacity
increases can proceed while only InstanceRefresh is suspended. Paused original
instances keep their target-group registrations until replacement resumes.
Explicitly detached instances leave refresh ownership and are not adopted again
when the refresh resumes. Recovery of an accepted EC2 launch keeps the source
identity recorded for that attempt even if the group configuration has changed.
Older attempts without a recorded source use the available EC2 instance metadata
without assigning the current launch template to the recovered instance.
This does not implement rolling health-percentage limits, checkpoints, rollback, or cancellation. Refreshes saved by older versions without replacement ownership retain the previous reconciliation behavior. Storage reload coverage does not imply an atomic transaction spanning Auto Scaling and EC2 after a process crash.
Load Balancer Attachment
| Operation | Notes |
|---|---|
AttachLoadBalancerTargetGroups |
Attaches ELB v2 target group ARNs; new instances auto-registered on InService |
DetachLoadBalancerTargetGroups |
Detaches target groups; instances deregistered |
DescribeLoadBalancerTargetGroups |
Lists target groups attached to a group |
AttachLoadBalancers |
Classic ELB attachment (stored; no ELB v1 routing) |
DetachLoadBalancers |
Classic ELB detachment |
DescribeLoadBalancers |
Lists classic ELBs attached to a group |
Traffic Sources
| Operation | Notes |
|---|---|
AttachTrafficSources |
Unified elb/elbv2/vpc-lattice attachment API; stored per identifier with its type |
DetachTrafficSources |
Removes a traffic source by identifier |
DescribeTrafficSources |
Lists attached sources, optionally filtered by type; every source reports InService |
Lifecycle Hooks
| Operation | Notes |
|---|---|
PutLifecycleHook |
Creates or updates a hook: LifecycleTransition, DefaultResult, HeartbeatTimeout |
DescribeLifecycleHooks |
Lists hooks for a group |
DeleteLifecycleHook |
Removes a hook |
CompleteLifecycleAction |
Signals CONTINUE or ABANDON for a pending lifecycle action |
RecordLifecycleActionHeartbeat |
Extends the heartbeat timeout for an in-progress lifecycle action |
Scaling Policies
| Operation | Notes |
|---|---|
PutScalingPolicy |
Creates or updates a policy: SimpleScaling fields or TargetTrackingScaling with predefined metric, target value, and estimated warmup |
DescribePolicies |
Lists policies filtered by group or policy name, including stored target tracking configuration |
DeletePolicy |
Removes a scaling policy |
Scheduled Actions
| Operation | Notes |
|---|---|
PutScheduledUpdateGroupAction |
Creates or updates a schedule: recurrence, time zone, start/end time, capacity bounds |
DescribeScheduledActions |
Lists scheduled actions filtered by group or action name |
DeleteScheduledAction |
Removes a scheduled action |
Warm Pools
| Operation | Notes |
|---|---|
PutWarmPool |
Full replace per the wire model: omitted fields reset to defaults; MaxGroupPreparedCapacity=-1 clears the value |
DescribeWarmPool |
Returns the stored configuration; also embedded in DescribeAutoScalingGroups per the AutoScalingGroup shape |
DeleteWarmPool |
Removes the configuration; idempotent when none exists |
Activities
| Operation | Notes |
|---|---|
DescribeScalingActivities |
Returns the activity log for a group; activities recorded on scale-out and scale-in events |
Metadata
| Operation | Notes |
|---|---|
DescribeTerminationPolicyTypes |
Returns the standard termination policy names |
DescribeAccountLimits |
Returns max group / config / instance limits |
DescribeLifecycleHookTypes |
Returns autoscaling:EC2_INSTANCE_LAUNCHING and autoscaling:EC2_INSTANCE_TERMINATING |
DescribeAdjustmentTypes |
Returns the four standard adjustment types |
DescribeMetricCollectionTypes |
Returns standard metric and granularity names |
DescribeAutoScalingNotificationTypes |
Returns all notification type names |
Suspended Process Reasons
SuspendProcesses records when each newly suspended process entered that state.
DescribeAutoScalingGroups returns SuspensionReason in the form
User suspended at 2026-10-18T16:00:00Z. Repeating a suspension preserves its
original time. Resuming a process removes its recorded time; suspending it again
starts a new interval.
Saved groups without a recorded suspension time still report the process name and omit the optional reason. Floci does not invent a date for those existing suspensions. A repeated suspension leaves an unknown time unknown until the process is resumed and suspended again.
Capacity Reconciler (Phase 2)
Floci runs a background reconciler (10 s fixed rate) that keeps each group's InService instance count aligned with DesiredCapacity:
- Scale-out: calls
RunInstanceswith the group's launch configuration; new instances are tracked asPendinguntil the EC2 state transitions torunning, at which point they move toInServiceand are registered with all attached ELB v2 target groups. - Scale-in: selects InService instances not protected from scale-in, deregisters them from target groups, then calls
TerminateInstances. - Activity records are written on each scale-out and scale-in event.
SuspendProcesses pauses desired-capacity scale-out for Launch and scale-in for
Terminate. The desired count remains stored, and ResumeProcesses allows the
next reconciliation pass to continue toward it. Omitting process names suspends
or resumes all processes. Suspending another process does not pause these capacity
adjustments. Suspension and resumption wait for any desired-capacity adjustment already
in progress for that group, so a completed suspension cannot be bypassed by an earlier
reconciliation check.
New owned refresh replacements also pause for InstanceRefresh, Launch, or
Terminate, as described above. Explicitly requested termination and stale-instance
cleanup continue independently.
Other suspended process names are stored and returned but do not pause their
associated activities.
Launch Source Compatibility
New launch configurations preserve their original base64 user data when launching instances, including binary and gzip payloads. Configurations derived from an instance retain its original encoding when available. Existing stored configurations retain their previous interpretation because older records mixed encoded input and decoded text; recreate a configuration to use byte-preserving launches. When deriving a configuration from an instance, omitted and blank user-data overrides continue to inherit the source instance's data. Creation checks the final selected data before saving: it must pass the shared EC2 decoder's base64 and 16 KiB raw-data checks. The decoder also rejects malformed gzip and expansion beyond 10 MiB; this is Floci's execution safety limit, not an AWS API limit. Invalid marked data in an older saved configuration is contained as a launch failure so reconciliation can still save the group and check refresh progress.
Direct and mixed launch templates retain the selected version's original user-data encoding for instance attributes and metadata, including compressed and binary payloads. Execution still uses decoded text. Older templates that store only execution text retain that text through a UTF-8 fallback.
Auto Scaling groups preserve either a launch configuration, a top-level launch template, or a MixedInstancesPolicy. These launch sources are mutually exclusive in create/update requests. When a mixed instances policy is supplied, Floci stores and returns:
LaunchTemplate.LaunchTemplateSpecification.LaunchTemplateIdLaunchTemplate.LaunchTemplateSpecification.LaunchTemplateNameLaunchTemplate.LaunchTemplateSpecification.VersionLaunchTemplate.Overrides.member.N.InstanceTypeLaunchTemplate.Overrides.member.N.WeightedCapacityLaunchTemplate.Overrides.member.N.InstanceRequirementsInstancesDistribution.OnDemandBaseCapacityInstancesDistribution.OnDemandPercentageAboveBaseCapacityInstancesDistribution.SpotAllocationStrategy
An override selects instance types either by name or by attribute. Setting both InstanceType and
InstanceRequirements on the same override raises ValidationError, matching AWS. An override that
specifies InstanceRequirements must specify both VCpuCount and MemoryMiB, the two members the
AWS model marks required on that shape, and raises ValidationError otherwise. Every member of the
InstanceRequirements shape round-trips except BaselinePerformanceFactors, which is accepted and
dropped.
WeightedCapacity must be an integer from 1 to 999 written in at most 32 characters, and once
one override sets it every override must, as the AWS model requires. Either rule raises
ValidationError otherwise.
A group uses attribute-based instance type selection when the mixed instances policy left in effect
by the request carries at least one launch template override with InstanceRequirements. On create
that is the policy the request supplies. On update it is the policy the request supplies, the stored
policy when the request names no launch source, or none when the request switches the group to a
launch configuration or a plain launch template.
Optional Group Fields
CreateAutoScalingGroup and UpdateAutoScalingGroup both accept the fields below, and
DescribeAutoScalingGroups returns each one only when the group has a value for it. A group that
never set a field omits it from the response rather than reporting a default.
| Field | Notes |
|---|---|
DesiredCapacityType |
One of units, vcpu, memory-mib. Any other value raises ValidationError. AWS supports it for attribute-based instance type selection only, so vcpu and memory-mib raise ValidationError unless the effective mixed instances policy uses InstanceRequirements. units is the documented default and is always accepted |
CapacityRebalance |
Stored and echoed as a boolean |
MaxInstanceLifetime |
Seconds. Must be 0 or at least 86400. 0 means no maximum and is echoed back as 0 |
DefaultInstanceWarmup |
Seconds. Pass -1 to remove a value already set, after which the field is omitted again |
ServiceLinkedRoleARN |
Stored and echoed as given, 1 to 1600 characters. Floci does not check that the role exists, and a group that never set it omits it rather than reporting the default AWSServiceRoleForAutoScaling role |
InstanceMaintenancePolicy |
MinHealthyPercentage 0 to 100 and MaxHealthyPercentage 100 to 200, both required, at most 100 apart. -1 on both clears a policy already set. Any other combination raises ValidationError |
AvailabilityZoneDistribution |
CapacityDistributionStrategy is one of balanced-only, balanced-best-effort, reservations-then-balanced |
CapacityReservationSpecification |
CapacityReservationPreference is one of capacity-reservations-only, capacity-reservations-first, none, default. CapacityReservationTarget (CapacityReservationIds, CapacityReservationResourceGroupArns) round-trips, accepts at most one ID or resource group ARN, and is rejected alongside none. Each ID is 1 to 255 characters of [A-Za-z0-9-_/] and each resource group ARN is 1 to 1600 characters |
Except for CapacityReservationSpecification, these fields are stored and reported only.
The group capacity reservation preference applies to scale-out and replacement launches.
default or an omitted preference retains the launch template specification. none launches
without consuming reservations. capacity-reservations-only requires matching reserved capacity;
capacity-reservations-first falls back to unreserved On-Demand capacity on a capacity shortage.
An omitted group target inherits the template target; with neither target, matching open
reservations are eligible. Updating the group affects subsequent launches, not existing instances.
Missing or invalid targets do not trigger On-Demand fallback. Resource group targeting remains
unsupported, as in EC2, and reports a failed scaling activity without allocating an instance.
Scaling Policy Compatibility
Target tracking policies preserve TargetTrackingConfiguration for predefined metrics. DescribePolicies returns PredefinedMetricSpecification.PredefinedMetricType, TargetValue, and EstimatedInstanceWarmup when present.
Configuration
| Variable | Default | Description |
|---|---|---|
FLOCI_SERVICES_AUTOSCALING_ENABLED |
true |
Enable or disable the service |
Usage Example
# Create a launch configuration
aws autoscaling create-launch-configuration \
--launch-configuration-name my-lc \
--image-id ami-12345678 \
--instance-type t3.micro
# Create a group targeting desired=2
aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name my-asg \
--launch-configuration-name my-lc \
--min-size 1 \
--max-size 5 \
--desired-capacity 2 \
--availability-zones us-east-1a
# Attach an ELB v2 target group
aws autoscaling attach-load-balancer-target-groups \
--auto-scaling-group-name my-asg \
--target-group-arns arn:aws:elasticloadbalancing:us-east-1:000000000000:targetgroup/my-tg/abc123
# Watch instances appear
aws autoscaling describe-auto-scaling-groups \
--auto-scaling-group-names my-asg
# Scale out
aws autoscaling set-desired-capacity \
--auto-scaling-group-name my-asg \
--desired-capacity 3
Launch configurations accept an IAM instance profile name or ARN. Unknown and foreign profiles fail creation with ValidationError. At launch, the reconciler resolves a stored name to its ARN in the owning account. CreateAutoScalingGroup and UpdateAutoScalingGroup refuse, with ValidationError, a launch template that names both an instance profile name and an ARN, directly or through the mixed instances policy.
Launch-configuration metadata options (HttpTokens, HttpEndpoint, and HttpPutResponseHopLimit) round-trip through Query and CloudFormation and reach EC2 launches. CloudFormation resolves intrinsics inside the block, so Fn::If and AWS::NoValue can select or omit the block or any of its members. When the structure is omitted it stays absent from DescribeLaunchConfigurations; a supplied partial structure reports defaults for unspecified fields. Launch templates, mixed-instance templates and EC2 Fleet launches likewise forward their existing metadata options.