feat(azure/ri-exchange): list exchangeable Azure VM reservations (refs #473) - #595
Conversation
…#473) Add ListExchangeableReservations to the Azure compute client, returning all VM reservations with ProvisioningState==Succeeded and InstanceFlexibility==On (the criteria Azure requires for the cross-SKU/cross-region exchange path). Wire a new GET /api/ri-exchange/azure-instances handler that requires view:purchases permission and accepts an optional ?subscription_id= query parameter. Both layers are covered by unit tests using injected stubs -- no live Azure credentials needed in CI. The find-compatible-offerings (CalculateExchange) and execute steps are tracked separately in a follow-up issue.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThis PR implements end-to-end Azure Reserved Instance exchange discovery. It adds the Azure SDK reservations module, implements provider-side filtering and pagination to identify exchangeable VM reservations meeting specific criteria (succeeded provisioning, On instance flexibility), exposes a new authenticated HTTP endpoint with test-injectable Azure client factories, and wires the routing. The solution enforces eligibility via provisioning state, resource type, and instance flexibility checks, and gracefully handles ARM resource ID parsing and missing optional fields. ChangesAzure RI Exchange Discovery
Sequence DiagramsequenceDiagram
participant User as User/Client
participant Router as Router
participant Handler as Handler
participant Factory as Azure<br/>Exchange Factory
participant Compute as Compute Client
participant ARM as ARM Pager
User->>Router: GET /api/ri-exchange/azure-instances
Router->>Handler: listExchangeableAzureRIs(ctx, req)
Handler->>Handler: Check view:purchases permission
Handler->>Handler: Read subscription_id from query
Handler->>Factory: buildAzureExchangeClient(subscriptionID)
Factory->>Compute: NewDefaultAzureCredential or stub
Compute-->>Factory: credential/error
Factory-->>Handler: azureExchangeClient or error
Handler->>Compute: ListExchangeableReservations(ctx)
Compute->>ARM: NewListAllPager (real or injected)
loop For each page
Compute->>ARM: NextPage(ctx)
ARM-->>Compute: page items
Compute->>Compute: isExchangeEligible filter
Compute->>Compute: convertToExchangeableReservation
end
Compute-->>Handler: []ExchangeableReservation or error
Handler->>Handler: Build ExchangeableAzureRIsResponse
Handler-->>User: JSON response
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes The PR introduces new types, filtering logic, and provider-level paging implementation across multiple files. Moderate complexity stems from ARM SDK integration details, eligibility predicate enforcement, and field extraction safety. The handler-level API integration follows established patterns. Review requires attention to eligibility criteria correctness, order ID parsing robustness, and error handling completeness. Possibly Related Issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
ListExchangeableReservationsto the Azure compute client, filtering tenant-wide VM reservations to those withProvisioningState==SucceededandInstanceFlexibility==On(the Azure exchange eligibility criteria)GET /api/ri-exchange/azure-instancesroute protected byview:purchasespermission; accepts optional?subscription_id=query parameterThis is the list half of Azure Convertible RI exchange parity. The find-compatible-offerings (CalculateExchange) and execute steps are tracked in a follow-up issue.
Test plan
providers/azuremodule:go test ./...-- 361 passinternal/apipackage:go test ./internal/api/...-- 1158 passSummary by CodeRabbit
Release Notes