Repository navigation
Conversation
…e reshape Pins pkg to LeanerCloud/cloud-commitments-go#584, whose reshape analysis accepts the region's offered instance types (WithOfferedInstanceTypes and RunAutoExchangeParams.OfferedInstanceTypes). The change is source-compatible; nothing is wired to it yet. The range also brings go#578 (RunAutoExchange fails closed on any mode other than "auto" or "manual") and go#584's skip of equal-capacity reshapes. Refs LeanerCloud#1206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…shape page getReshapeRecommendations now fetches the region's instance type catalog (ec2svc.Client.GetValidResourceTypes, DescribeInstanceTypeOfferings) and passes it to AnalyzeReshapingWithRecs, so targets are limited to offered sizes and a family the region does not offer gets a recommendation with a Reason instead of a target. A catalog error or an empty catalog logs a warning naming the region and falls back to the legacy size ladder. Nothing is cached, so the next request queries the catalog again. Refs LeanerCloud#1206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r reshapes The standalone RI-exchange task and the ladder's exchange runner now fetch the region's instance type catalog (GetValidResourceTypes) and pass it as RunAutoExchangeParams.OfferedInstanceTypes, so automated exchanges only target offered sizes and skip, with a reason, RIs whose family the region does not offer. Both paths now build their clients through newRIExchangeClients, and the ladder runner's post-construction body moves to runWithClients so tests can drive it with fakes. A catalog error or empty catalog logs a warning naming the region and keeps the legacy size ladder, uncached. Refs LeanerCloud#1206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
Brings in main's CI fixes (LeanerCloud#1236, LeanerCloud#1252) and CI changes since, so this PR gets a fresh CI run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review 2 (claude-fleet, cold): APPROVE 5bcb13b Merge order note: this PR bumps the pkg pin from 541e05e to e237996, and that range includes go#578.
Findings (none blocking on their own):
Attacked:
Verified locally, with GOTOOLCHAIN=go1.26.10 and no cloud credentials, under the heavy lock:
Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged. |
|
Merge-order note: this pin bump (541e05e..e237996) includes LeanerCloud/cloud-commitments-go#578, which makes the RI-exchange mode check fail closed. It should merge only after #1243 (ri_exchange_mode validation on PUT /api/config) is fixed and merged, and after the legacy-row query in #1243's body shows no stored mode other than |
|
VERDICT: APPROVE 5bcb13b PR #1246 (draft, @IAmJSD), head 5bcb13b, merge base 503eb2e (3 behind origin/main 2ded648). Findings (no blockers)
#1206 checklist vs code
Go-lib range (pkg-only source diff from the module cache)
Attacked / probes (all killed)
|
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: REQUEST_CHANGES Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rA1. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
Bring the branch up to date with main (7cde88e), which now validates RI exchange account IDs as 12-digit AWS account IDs (LeanerCloud#1170). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now refuses to record an RI exchange whose account ID is not a 12-digit AWS account ID (LeanerCloud#1170), so the "acct-1" fixture failed three standalone/* subtests of TestRIExchangeReshape_OfferedCatalog. Use the 123456789012 documentation placeholder instead; every assertion is kept. Refs LeanerCloud#1206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pick up LeanerCloud#1111 and LeanerCloud#1418 so CI runs against the fixed main (LeanerCloud#1418 fixes main's red purchase integration test). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Updated the branch. New head:
Checks on the merged tree:
|
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Non-blocking:
Attacked:
Body-stale:
From earlier reviews (confirmed): #1243 is still in REQUEST_CHANGES, so "merge after #1243" is not yet satisfiable. The stale Reviewer: rB24. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
…1468) The reshape analyzer returns target_instance_type "" and target_count 0 when it has no exchange target for an RI (a completely unused RI, or, since the go bump in #1246, a target capped at the units the account owns). The table rendered those rows as "0x " under Suggested and kept a live Exchange button that opened the modal with a target count of 0. Such rows now say "No exchange target" (the Reason column already explains why) and get a disabled Exchange button with no quote action. A no-target row that still carries cross-family alternatives keeps a live button, since the modal can preselect from them, and opens it with a count of 1 instead of 0. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Root cause
The reshape analysis in
cloud-commitments-gocan take the region's offered instance types since LeanerCloud/cloud-commitments-go#584 (exchange.WithOfferedInstanceTypes,RunAutoExchangeParams.OfferedInstanceTypes). The platform was pinned to an olderpkgand never passed a catalog. All three reshape paths therefore used the legacy size ladder. They could recommend a size the region doesn't sell, or a target in a family the region doesn't offer at all.Fix
d55e3c43):cloud-commitments-go/pkggoes from541e05e5fd29toe237996(the go#584 merge commit), the smallest bump that includes go#584. It is source-compatible.providers/awsstays ataeb8a6f, which already hasec2svc.Client.GetValidResourceTypes.internal/api):reshapeEC2ClientgainsGetValidResourceTypes.getReshapeRecommendationspassesexchange.WithOfferedInstanceTypes(...)toAnalyzeReshapingWithRecs. The new exportedapi.OfferedInstanceTypes(ctx, region, fetch)wraps the catalog fetch. On an error or an empty result it logs apkg/loggingwarning that names the region, then returns nil, so analysis falls back to the legacy ladder. It caches nothing, so every request queries the catalog again and a fallback is never reused.internal/server): the standalone task (handler_ri_exchange.go) and the ladder'sexchangeRunnerAdapter(ladder_write.go) both setRunAutoExchangeParams.OfferedInstanceTypesthrough the same helper. Both now build their clients withnewRIExchangeClients, so the wiring is shared and tested. The ladder adapter's body after client construction moved torunWithClientsso tests can drive it with fakes. Its error messages are unchanged.IAM:
ec2:DescribeInstanceTypeOfferingsis already granted in the Lambda/Fargate runtime roles, the CloudFormation stacks and the federation templates, so no IaC change is needed. If a deployment lacks the grant, the call fails, logs the warning and keeps the old behavior.Closes #1206
Merge order
This PR must merge after #1243 (
ri_exchange_modevalidation onPUT /api/config). Merged alone, the go#578 fail-closed check below would turn any invalid stored mode into failing scheduled runs, and nothing would stop the API from writing invalid modes again. It also conflicts with #1108 ininternal/server/ladder_write.go: whichever merges second must keep #1108's 4-eyes downgrade of unattended exchanges to manual.Behavior changes to be aware of
Reasonand no target.RunAutoExchangenow fails closed on anyRIExchangeModeother than exactlyautoormanual. A stored typo,""or"Auto"used to auto-execute. It now fails the scheduled run loudly. fix(config): validate ri_exchange_mode on PUT /api/config #1243 (validateri_exchange_modeonPUT /api/config, closes fix(config): validate RIExchangeMode on PUT /api/config #1196) is the companion fix.CancelPendingExchangesByOriginfails,RunAutoExchangenow returns that error before it starts any exchange, so the scheduled or ladder run fails. Before, the error was only logged and the run went on to create new exchanges while a stale pending one could still be approved. Dry runs are unchanged.common.DecodeServiceDetailsFornow returns an error wrappingcommon.ErrUntypedServiceDetailsfor a non-empty, non-nullDetailspayload on a service slug with no typed details. It used to return(nil, nil)and drop the payload.memorydb(CacheDetails) andnosql(NoSQLDetails) gained typed codecs so those rows still decode. In the platform, a stored rec on such a slug now fails the purchase (internal/purchase/execution.go) and the detail-identity checks ininternal/api/purchase_pricing.go. A malformed request body there is a 400.stampComputeCapacitystill ignores decode errors, andrecDetailsAvailabilityZoneonly decodesec2/compute.BuildReservationNamehas to shorten a name to the 60-character AWS cap (for example OpenSearchr6gd.large.search), it now keeps the random uniqueness suffix. It drops the timestamp first, then the payment segment, then truncates the SKU. Before, it dropped the suffix first, so long names were deterministic and a legitimate repurchase could collide. For RDS, ElastiCache, MemoryDB and OpenSearch this only affects reservation IDs built when no idempotency token is passed. Purchases with a token still useIdempotentReservationID. The EC2Nametag, a display tag only, is always built this way. The bump changes this forproviders/awstoo, because Go's minimum version selection resolves itspkgdependency to this pin.Reason: "instance family not offered in region (<family>)..."and no target. Scheduled and ladder runs record it inSkippedwith that reason and never look up an offering or request a quote for it.DescribeInstanceTypeOfferingscall (paginated at 1000). I added no caching. The issue requires that the fallback not be cached, and caching successful catalogs could be a follow-up if the latency matters.Frontend follow-up for the UI owner
No frontend files changed. Two things to check:
AlternativeTargets, because RIs with no strict downsize are now skipped.target_instance_typeand areasonsaying the family isn't offered in the region. The reshape table should show the reason rather than an empty target, or treat these like the existing "completely unused" no-target rows.Verification
All evidence is unit, mock or fixture based. No real AWS calls were made. Tests ran with
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/nullbecause this machine's default AWS profile is invalid.go build ./...,go vet ./internal/api/ ./internal/server/, andgo vet -tags integrationon the same two packages: clean.go test ./internal/... ./cmd/... -count=1with only the pin bump applied: all pass.go test ./internal/api/ ./internal/server/ ./internal/mocks/ -count=1: pass.go test -short -race ./internal/server/and-raceon the reshape tests ininternal/api: pass.go test -tags integration ./internal/api/ -run TestReshapeRecommendations_Integration(4 tests) and./internal/server/ -run TestRIExchangeAutoWorkers_ConcreteStoreAndFixtureClientpass.internal/api/reshape_offered_types_test.go:m5.2xlargeturns 1x m5.4xlarge at 50% into 2x m5.xlarge instead of 1x m5.2xlarge;Reason;OfferedInstanceTypes, including that a partial result returned next to an error is discarded.internal/server/ri_exchange_offered_types_test.go:newRIExchangeClientsroutes every call, includingGetValidResourceTypes;executeRIExchangeReshapeand the ladderrunWithClients(dry run), asserting the offering lookup target, the outcome target and count,Skippedreasons and the warnings.exchange.WithOfferedInstanceTypes(offered)fromgetReshapeRecommendationsfails all 3 handler catalog tests (output shows targetm5.2xlargewith noReason, and no warning).OfferedInstanceTypes:from the standalone params fails the 4standalone/*subtests.ladder/*subtests.golangci-lintv2.10.1run --allow-parallel-runners ./internal/api/... ./internal/server/..., with and without--build-tags integration: 0 issues.gocyclo -over 10 -ignore "_test\.go" internal/api internal/server: silent.getReshapeRecommendationsstays at 10 because the new call adds no branch.scripts/gosec-hook.shon the changed files: clean.make tidy-check: clean.--register-aws,scripts/setup-git-secrets.shand.gitallowed. All 14 changed files were tracked. Planted fake account-ID and AKIA keys were flagged (rc=1), and the clean scan passed (rc=0).scripts/test-git-secrets-allowlist.sh: 137 PASS, 0 FAIL.Not covered: I didn't run against a real AWS account, so a live
DescribeInstanceTypeOfferingsresponse and the real IAM grant are untested. I also didn't exercise the production client construction inhandleRIExchangeReshapeorexchangeRunnerAdapter.RunAutoExchange, since it needs real AWS config. The compiler checks that*ec2svc.ClientsatisfiesriExchangeEC2, and the tests covernewRIExchangeClientsitself.Out of scope
RIExchangeModevalidation), see above.pkgpaste237996(go#587 removes exported API; go#603 and go#609 renameProviderConfig) and bumpingproviders/*.A maintainer, please mirror the issue's triage labels on this PR:
priority/p2,severity/low,urgency/this-quarter,impact/few,effort/m,type/feat,triaged.🤖 Generated with Claude Code