Repository navigation
fix(E3671): Set gp3 Iops limits per resource type - #4866
Conversation
|
Thanks for this — the 80000 figure is right, and I confirmed it by deployment rather than from the docs: an The problem is that
So raising the shared That includes this PR's own new test case.
What I think this needs, which is more than a one-number change:
Two schema files rather than one, because the numbers differ, with the keyword list split across them. One more thing worth knowing before this lands: the current Happy to take the split myself if you would rather not expand the scope here. The core finding is yours and correct. |
|
Thanks for testing this against real deployments, that table made the split straightforward. Done in 98ab126: E3671 now covers |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4866 +/- ##
=======================================
Coverage 94.68% 94.69%
=======================================
Files 439 440 +1
Lines 16016 16043 +27
Branches 3111 3113 +2
=======================================
+ Hits 15165 15192 +27
Misses 468 468
Partials 383 383
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
EBS raised the gp3 IOPS maximum from 16,000 to 80,000 in September 2025, but the gp3 branch of the block device mapping extension schema still capped Iops at 16000, so E3671 rejected valid values such as 20000. Raise the maximum to 80000. The io1 and io2 limits and the gp3 minimum are unchanged.
The block device mapping schema was shared by every resource type, but the APIs behind them enforce different limits. Auto Scaling launch configurations still reject gp3 Iops above 16000, so they now use their own schema with that maximum, while EC2 instances keep the 80000 maximum. Launch templates and Spot Fleet launch specifications are not validated when the stack is created, so their checks move to a new warning, W3672. AWS::OpsWorks::Instance is dropped from the keyword list because the type is no longer in the schema set.
98ab126 to
861347b
Compare
* fix(E3671): allow gp3 Iops from 100 on AWS::EC2::Instance
The gp3 branch of the EC2 instance block device mapping extension
applied a minimum of 3000 to Iops, but EC2 accepts any value from 100
upward on this path and clamps it up to 3000. Every value from 100 to
2999 was reported as an error on templates that deploy successfully.
Verified by deployment in us-east-1 on 2026-10-26, same template shape
with only Iops changed:
Iops: 2999 CREATE_COMPLETE; DescribeVolumes reports the volume
provisioned at 3000 IOPS, so EC2 clamped the value up.
Iops: 50 ROLLBACK with "Volume iops of 50 is too low; minimum is
100. (Service: Ec2, Status Code: 400)".
So the hard floor on this path is 100, matching the io1 and io2 branches
in the same file, which already use 100 and agree with the minimum the
service itself reports.
AWS::AutoScaling::LaunchConfiguration is left at 3000. That API
genuinely rejects lower values with "GP3 volumes must have between 3000
and 16000 IOPS.", so its own schema keeps the higher floor. The per-path
split that makes this possible landed in #4866.
Fixes #4929
* feat(W3673): warn when a gp3 Iops below 3000 is raised
Dropping the gp3 Iops minimum to 100 removed a false positive but left
the user with no signal at all. EC2 does not reject a gp3 Iops between
100 and 2999, it provisions the volume at the gp3 baseline of 3000, so
the stack deploys and the value in the template is not the value in
effect. Measured on live CloudFormation in us-east-1 on 2026-10-26: an
AWS::EC2::Instance with a gp3 Iops of 2999 reached CREATE_COMPLETE and
DescribeVolumes reported the volume at 3000 IOPS.
W3673 covers AWS::EC2::Instance only. AWS::AutoScaling::LaunchConfiguration
is deliberately excluded because it rejects the value outright with
"GP3 volumes must have between 3000 and 16000 IOPS.", which E3671 already
reports, and a warning beside that error would describe behaviour that
does not happen. AWS::OpsWorks::Instance is excluded because the type is
absent from the schemas, so E3006 fires first.
The warning stops at 100. Below that the volume is genuinely rejected
with "Volume iops of 50 is too low; minimum is 100." and E3671 reports
it, so one value never draws both a warning and an error.
A separate id rather than an extension of W3671: W3671 states that the
value is ignored, which is a different fact from the value being
adjusted, and its keyword list spans paths where no adjustment happens.
The docs/rules.md diff also picks up a stale E3688 description that
predates this change, because the file is generated.
* refactor(W3673): express the gp3 Iops warning as a schema extension
W3673 was imperative Python where a schema extension does the same job,
against the preference for the simplest rule type and out of step with
E3671 and W3672, which are both schema driven on the same path. The
condition moves to blockdevicemappings_gp3_iops.json as an if/then with
a negated range, and the rule keeps only the message.
This also fixes a fault in the imperative version. It matched
'VolumeType' case insensitively, so a value of 'GP3' drew the warning
on top of the E3030 enum error it already earns, which is the same
"warning beside an error about one value" problem that keeps this rule
off AWS::AutoScaling::LaunchConfiguration. 'VolumeType' is a case
sensitive enum, so the schema uses a plain const and 'GP3' now reports
E3030 alone.
A negated range needs an explicit type guard. Without "type": "number"
inside the "not", the inner schema is vacuously true for anything that
is not a number, the negation then fails, and the warning fires on an
unresolved Ref, GetAtt or Fn::If and on every non scalar. Removing the
guard fails four of the silence tests, which is what pins it.
Behaviour on resolvable values is unchanged: verified by real lint that
gp3 Iops of 100 and 2999 warn, 50 reports E3671 alone, 3000 and 80000
are silent, Auto Scaling still reports E3671 with no warning beside it,
and the good-fixture sweep is byte identical to a run with no rule.
Issue #, if available:
Fixes #4836
Description of changes:
E3671 capped gp3
Iopsat 16000, which was the EBS limit until September 2025. EC2 now allows 80,000, so the template in the issue gets a false positive at 20000. After review, the limits depend on where the mapping sits:AWS::EC2::Instance: E3671, gp3 maximum 80000.AWS::AutoScaling::LaunchConfiguration: E3671 with its own schema, gp3 maximum 16000, since Auto Scaling still rejects anything higher.AWS::EC2::LaunchTemplateandAWS::EC2::SpotFleet: a new warning, W3672, with the 80000 limits, because CloudFormation does not validate them at create time. ExistingE3671ignores on those resources will not cover W3672.AWS::OpsWorks::Instanceis dropped from the keyword list.The 500 IOPS per GiB ratio is still not checked. The release schema export takes one schema per rule, so it still shows 80000 for launch configurations. Tests cover both E3671 schemas and the new warning; the full suite shows no new failures, and pre-commit passes on the changed files.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.