Skip to content

fix(aws): create subnets in an availability zone that offers the instance types - #878

Open
abrarshivani wants to merge 1 commit into
NVIDIA:mainfrom
abrarshivani:fix/aws-availability-zone-selection
Open

abrarshivani wants to merge 1 commit into
NVIDIA:mainfrom
abrarshivani:fix/aws-availability-zone-selection

Conversation

@abrarshivani

@abrarshivani abrarshivani commented Oct 5, 2026 •

Copy link
Copy Markdown

Description

Create subnets in an Availability Zone that offers the requested instance types, and fail the pre-flight when no zone offers them or the pinned zone doesn't.

Motivation

  • The gpu-driver-container precompiled CI runs g5g.xlarge in us-west-2, which us-west-2d doesn't offer.
  • When AWS puts the subnet in us-west-2d, RunInstances fails with Unsupported.
  • The rollback often fails with DependencyViolation and leaks the VPC.
  • Not a one-off: each of the ~10 arm64 jobs per nightly can hit it, and retries don't help.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📝 Documentation update
  • 🔧 Refactoring (no functional changes)
  • 🧪 Test improvements
  • 🔨 Build/CI changes

Changes Made

  • Find the available standard zones that offer every needed instance type.
  • Pick the first in sorted order, skipping Local and Wavelength Zones.
  • Create every subnet in that zone, and fail subnet creation if no zone was selected.
  • Fail Create, CreateCluster and DryRun before creating anything when no zone qualifies.
  • Without the zone discovery permissions, log a warning and let AWS choose the zone as before; reject a pinned zone.
  • Ignore the worker type when a cluster has zero workers.
  • Add an optional availabilityZone to instance and cluster.
  • Record the chosen zone in status and show it in holodeck describe.
  • Keep older cache files without the zone loading.
  • Add the two EC2 calls to the client interface, fake and mocks.
  • Make the fake reject invalid NextToken values.
  • Document the field, use placeholder zones, and list the recommended IAM permissions.

Testing

  • Unit tests added/updated

  • E2E tests added/updated

  • Manual testing performed

  • Cover partial, missing and pinned zone offerings.

  • Cover Local, unavailable and constrained zones.

  • Cover cluster type intersection and zero-worker clusters.

  • Cover the cache round trip and describe.

  • Cover zone lookup failures, the missing-permission fallback, and subnet creation without a selected zone.

  • Use us-west-2, the fake's zone region, in every zone-selection test.

  • Confirm each new test fails without its fix.

Test Commands Run

go build ./...
go vet ./...
make lint
make test
go test ./tests/ -args -ginkgo.label-filter=mock

Checklist

  • My code follows the project's coding conventions
  • I have performed a self-review of my code
  • I have commented my code where necessary
  • I have updated the documentation (if applicable)
  • My changes generate no new warnings
  • I have added tests that prove my fix/feature works
  • New and existing tests pass locally
  • I have signed off my commits (git commit -s)

Additional Notes

  • ec2:DescribeAvailabilityZones and ec2:DescribeInstanceTypeOfferings are recommended. Without them Holodeck falls back to AWS choosing the zone, so the real-AWS smoke job exercises zone selection only once cnt-ci has them.
  • Offerings don't guarantee capacity, so InsufficientInstanceCapacity can still occur. Retrying another zone could be a follow-up.
  • describe shows the spec region, which can differ from the zone's region under AWS_REGION.
  • make generate doesn't run on Go 1.26. The new string fields need no deepcopy changes.

Copilot AI balanced review requested due to automatic review settings October 5, 2026 23:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The status update loop mutates copied properties and cannot reliably persist or add the selected zone.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds AWS Availability Zone selection based on requested instance-type availability, preventing unsupported instance launches and leaked networking resources.

Changes:

  • Selects or validates an Availability Zone during pre-flight checks.
  • Pins subnets to the selected zone and persists it in status.
  • Extends AWS fakes, tests, CLI output, API types, and documentation.
File Description
tests/​e2e_mock_test.go Verifies subnet and cached zone consistency.
pkg/​testutil/​mocks/​aws.go Mocks new EC2 discovery operations.
pkg/​provider/​aws/​status.go Persists the selected zone in status.
pkg/​provider/​aws/​image.go Implements zone discovery and selection.
pkg/​provider/​aws/​image_test.go Aligns tests with fake region data.
pkg/​provider/​aws/​create.go Pins created subnets to the selected zone.
pkg/​provider/​aws/​create_test.go Tests single-node zone behavior.
pkg/​provider/​aws/​cluster.go Carries the selected zone into cluster creation.
pkg/​provider/​aws/​cluster_test.go Tests cluster zone intersections and constraints.
pkg/​provider/​aws/​cache_test.go Tests zone cache compatibility.
pkg/​provider/​aws/​aws.go Adds zone state and cache handling.
pkg/​provider/​aws/​aws_test.go Aligns provider tests with seeded zones.
pkg/​provider/​aws/​aws_ginkgo_test.go Extends dry-run and cache assertions.
internal/​aws/​ec2_client.go Adds EC2 zone-discovery methods.
internal/​aws/​awsfake/​store.go Adds fake zone and offering data.
internal/​aws/​awsfake/​ec2.go Implements fake discovery and subnet recording.
internal/​aws/​awsfake/​awsfake_test.go Tests fake offerings, filtering, and pagination.
docs/​prerequisites.md Documents required IAM permissions.
docs/​guides/​multinode-clusters.md Documents cluster zone configuration.
docs/​commands/​create.md Documents automatic and pinned selection.
cmd/​cli/​describe/​describe.go Displays the selected zone.
cmd/​cli/​describe/​describe_test.go Tests zone display data.
api/​holodeck/​v1alpha1/​types.go Adds optional zone fields.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/provider/aws/status.go
@abrarshivani abrarshivani self-assigned this Oct 5, 2026
ArangoGutierrez
ArangoGutierrez previously approved these changes Oct 6, 2026

@ArangoGutierrez ArangoGutierrez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. Choosing the subnet zone from instance type offerings fixes a real failure mode where RunInstances would return "Unsupported" after all the VPC networking already existed.

The checkInstanceTypes pre-flight now intersects DescribeInstanceTypeOfferings with the region's available standard zones (Local and Wavelength Zones are skipped) and puts both subnets in that one zone. If no zone offers every requested type, or a pinned availabilityZone doesn't offer them, holodeck create now fails before the VPC is created and lists the zones that would work. The zone is also recorded in status, so holodeck describe shows it.

@ArangoGutierrez
ArangoGutierrez dismissed their stale review October 6, 2026 09:34

Approved before CI was checked. E2E Real Smoke fails at the new zone pre-flight with a 403 on ec2:DescribeAvailabilityZones for the CI IAM user, so this is not ready to merge yet. Follow-up review to come.

@ArangoGutierrez ArangoGutierrez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The zone selection itself looks right, but it adds two IAM requirements to create and dryrun, and the real-AWS smoke job shows what that does to an identity without them: E2E Real Smoke fails in under a second with a 403 on DescribeAvailabilityZones for the cnt-ci user. The gpu-operator and device-plugin e2e jobs run under their own IAM identities, so they would hit the same wall the day this merges.

Comment thread pkg/provider/aws/image.go
@coveralls

coveralls commented Oct 6, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 38002756987

Coverage increased (+1.4%) to 51.849%

Details

  • Coverage increased (+1.4%) from the base build.
  • Patch coverage: 26 uncovered changes across 5 files (183 of 209 lines covered, 87.56%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
pkg/testutil/mocks/aws.go 8 0 0.0%
internal/aws/awsfake/store.go 35 29 82.86%
internal/aws/awsfake/ec2.go 58 53 91.38%
pkg/provider/aws/status.go 5 1 20.0%
cmd/cli/describe/describe.go 7 4 57.14%
Total (9 files) 209 183 87.56%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 11952
Covered Lines: 6197
Line Coverage: 51.85%
Coverage Strength: 0.52 hits per line

💛 - Coveralls

@ArangoGutierrez ArangoGutierrez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround. Falling back to AWS zone placement on UnauthorizedOperation keeps create and dryrun working for identities that lack the two new permissions, while a pinned availabilityZone still fails loudly.

The real-AWS smoke job now passes through the fallback (its log carries the new warning for g4dn.xlarge), so the zone-aware path is exercised only by the fake until cnt-ci gets ec2:DescribeAvailabilityZones and ec2:DescribeInstanceTypeOfferings. Granting those is a follow-up on our side.

@abrarshivani
abrarshivani force-pushed the fix/aws-availability-zone-selection branch from b834516 to bc5023e Compare October 9, 2026 23:06
@abrarshivani

Copy link
Copy Markdown
Author

Thanks. Sounds good.

@abrarshivani
abrarshivani enabled auto-merge October 9, 2026 23:14
@abrarshivani
abrarshivani disabled auto-merge October 9, 2026 23:51
…ance types

Holodeck created its subnets without an Availability Zone, so AWS picked
one. Not every zone in a region offers every instance type, and the
pre-flight check only validated instance types at the region level. The
gpu-driver-container precompiled CI hits this with g5g.xlarge in
us-west-2: when the subnet lands in us-west-2d, RunInstances fails with

  Unsupported: Your requested instance type (g5g.xlarge) is not
  supported in your requested Availability Zone (us-west-2d).

after the VPC and its networking already exist, and the rollback that
follows can fail with DependencyViolation and leak the VPC.

The pre-flight now asks DescribeInstanceTypeOfferings which zones offer
the instance types the environment needs. For clusters that is the
control-plane type plus the worker type, but only when there are workers
to launch, so a control-plane-only cluster is not rejected over a worker
type it never uses. Only the region's standard zones in the available
state are considered, since Local and Wavelength Zones sort first and
support only a subset of services, and the first matching zone in sorted
order is chosen. If no zone offers every type, Create(), CreateCluster()
and DryRun() fail before anything is created. Every subnet Holodeck
creates, including both subnets of a cluster, is placed in the chosen
zone. A new optional availabilityZone field on the instance and cluster
specs pins the zone; the pre-flight rejects it if that zone does not
offer the requested types and lists the zones that do.

An identity without the ec2:DescribeAvailabilityZones or
ec2:DescribeInstanceTypeOfferings permission gets UnauthorizedOperation
from the zone discovery calls. In that case, and only when no
availabilityZone is set, the pre-flight logs a warning naming both
permissions and leaves the zone unselected, so the subnets are created
without AvailabilityZone and AWS chooses it as before. A pinned
availabilityZone fails instead, because it cannot be validated, and any
other error from the discovery calls still fails the pre-flight. The
subnet functions refuse an empty zone unless the pre-flight recorded
this fallback, so a path that skips the pre-flight cannot silently let
AWS pick the zone. The error code is read through the ErrorCode method
that smithy.APIError defines, which keeps smithy-go an indirect
dependency. The prerequisites page lists the two permissions as
recommended and describes what happens without them.

The selected zone is stored as an availability-zone property in
.status.properties for single-node environments and clusters, and
holodeck describe shows it in the provider section and in its JSON and
YAML output as provider.availabilityZone. Existing property names are
unchanged, and a cache file written before this change has no zone,
which describe omits.

To test this, the EC2Client interface, the fake and the mock client gain
DescribeAvailabilityZones and DescribeInstanceTypeOfferings. The fake
seeds us-west-2a through us-west-2d, can restrict an instance type to
some zones, add Local Zones or change a zone's state, honours the
zone-type, state and instance-type filters, and pages offerings two at a
time so callers have to follow NextToken. Tests that run the pre-flight
against the fake use us-west-2, the only region whose zones it knows,
and the mock e2e suite sets that region after loading its shared configs.

Signed-off-by: Abrar Shivani <ashivani@nvidia.com>
@abrarshivani
abrarshivani force-pushed the fix/aws-availability-zone-selection branch from bc5023e to 33c4768 Compare October 9, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants