Skip to content

fix(azure): RI exchange silently forces AppliedScopeType to Shared, reallocating the discount #57

Description

@cristim

Summary

An Azure RI exchange executed through POST /api/ri-exchange/azure-instances/exchange silently forces every acquired reservation to AppliedScopeType = Shared, discarding whatever scope the source reservation had. That is a silent reallocation of real money between cost centres, mentioned in neither the request nor the response.

Where

  • providers/azure/services/compute/exchange_operations.go defaults to Shared when tgt.AppliedScopeType is nil.
  • toAzureExchangeTargets (internal/api/handler_ri_exchange.go) never sets it.
  • AzureExchangeTargetBody has no such field, and openapi.yaml documents none - so no caller can control it.
  • ExchangeableReservation does not carry the source's applied scope either, so it cannot currently be preserved even in principle.

Concrete scenario

A reservation is deliberately Single-scoped to the prod subscription for chargeback. It is SKU-swapped through this endpoint and comes back Shared. Dev/test workloads now absorb the discount and prod pays on-demand. Nothing in the API surface told the caller this would happen.

Fix direction (any one, in preference order)

  1. Carry the source's AppliedScopeType (and applied scopes) through the exchange - requires adding the field to ExchangeableReservation so the tenant listing surfaces it.
  2. Expose applied_scope_type on AzureExchangeTargetBody and require it, so the caller states intent explicitly.
  3. At minimum, document the non-preservation in openapi.yaml and in the handler's response, so the behaviour is at least not silent.

Found during adversarial review of PR LeanerCloud/cloud-commitments-cli#1515 (Azure RI exchange execute). Out of scope for that PR, which fixed the Regions-constraint source gap.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions