Skip to content

extract/publish do not model the built-in **managed** gateway's API assignments #266

Description

Command that triggered the bug

extract / publish

Expected behavior

Summary

APIOps captures and publishes API↔gateway assignments only for self-hosted / custom
gateways (the ones returned by GET /service/gateways). The built-in managed gateway
(id managed) is never extracted, so its per-API membership is not represented in
artifacts and is never reconciled on publish. As a result the source and target diverge
whenever an API's managed-gateway membership differs from the target default.

Expected behavior

The target API's gateway set matches the source of truth. Given the source (dev) API is
assigned to a self-hosted gateway only (explicitly removed from the managed gateway):

Gateways: my-selfhosted-gateway

publishing the extracted artifacts should reproduce exactly that set on the target —
self-hosted only, not on the managed gateway.

Actual behavior

Actual behavior

After extract (self-hosted only) + publish to a fresh target, the API ends up on both
gateways, because APIM auto-adds a newly created API to the managed gateway and APIOps
never removes it:

Gateways: Managed  my-selfhosted-gateway

The self-hosted assignment is correct; the extra Managed assignment is silent drift
that APIOps cannot currently express or reconcile.

Root cause

  • extract iterates gateways via GET /service/gateways, which returns only self-hosted
    gateways. The managed gateway is not in that list, so no gateways/managed/apis.json
    artifact is produced.
  • publish only adds associations from artifacts; it has no desired-state record for
    the managed gateway, so it cannot remove an API from managed to match the source.

Impact

  • dev→prod config drift for any API whose managed-gateway membership is not the default
    (e.g. APIs intentionally served only by a self-hosted/workspace gateway).
  • The drift is silent — publish reports success while the gateway set does not match the
    source of truth.

Possible approaches (for discussion before implementation)

This is a design decision because reconciling managed membership is opinionated and
involves DELETE behavior:

  1. Extract managed membership explicitly. Query GET /service/gateways/managed/apis
    directly (works even though managed is absent from the gateways list) and write
    gateways/managed/apis.json. Publish then reconciles managed assignments like any
    other gateway (add missing, and — under --delete-unmatched — remove extras).
    • Caveat: on classic APIM most APIs are on managed by default, so the managed list can
      be large; publishing it is mostly redundant except for the intentional removals.
  2. Record only the negative state (APIs explicitly removed from managed) and apply the
    removal on publish. Smaller footprint but a new artifact concept.
  3. Document as a known limitation and require a manual step for the removal case:
    az rest --method delete --url ".../service/{svc}/gateways/managed/apis/{api}?api-version=2024-05-01"
    

Current workaround

Remove the API from the managed gateway on the target manually:

az rest --method delete \
  --url "https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ApiManagement/service/{svc}/gateways/managed/apis/{api}?api-version=2024-05-01"

apiops CLI version

1.0.0

Environment details

  • Azure/apiops-cli main
  • Commands: extract, publish

CI/CD environment

None

Is this bug blocking you?

None

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

close:fixedFixed by a previous PR or releasetype:bugSomething broken

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions