wso2 / wso2/api-platform

Remove or implement unwired APIGateway CRD spec fields

Open
#3,287 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area/Operator Type/Improvement
Dominant language
Go
Stars
71
Forks
111
Avg merge
1d 14h
Merged PRs (30d)
110

Description

Description

The APIGateway CRD (gateway.api-platform.wso2.com/v1) defines several typed spec fields that the API server accepts but the operator's reconcile/deploy path silently ignores, so setting them has no effect on the deployed gateway. The only field that actually configures the gateway today is spec.configRef (a ConfigMap of Helm values deep-merged over the operator default). This is a confusing false affordance — e.g. a user sets spec.infrastructure.image or spec.infrastructure.replicas and nothing changes.

Root cause: buildCRValuesOverlay (kubernetes/gateway-operator/internal/controller/apigateway_controller.go:757-779), the only function that turns spec.infrastructure into Helm values, reads only infra.Labels and infra.Annotations. Nothing reads infra.Image/RouterImage/Replicas/Resources/NodeSelector/Tolerations/Affinity, spec.storage, or spec.controlPlane.tls/tokenSecretRef. spec.controlPlane.host is only recorded in the operator's in-memory registry (registerGatewayInRegistry), never applied to the deployed gateway.

What is wired vs not (APIGateway CRD path):

Field Status
spec.apiSelector ✅ implemented (required)
spec.configRef ✅ implemented (the real config surface)
spec.infrastructure.labels / annotations ✅ implemented (→ commonLabels/commonAnnotations)
spec.controlPlane.host ⚠️ recorded in operator registry only, not deployed
spec.controlPlane.tls / tokenSecretRef ❌ ignored
spec.infrastructure.image / routerImage ❌ ignored
spec.infrastructure.replicas / resources ❌ ignored
spec.infrastructure.nodeSelector / tolerations / affinity ❌ ignored
spec.storage.* ❌ ignored

Sample CR showing the gap:

apiVersion: gateway.api-platform.wso2.com/v1
kind: APIGateway
metadata:
  name: sample-gw
  namespace: sample-gw
spec:
  apiSelector:                 # ✅ implemented (required)
    scope: Namespaced
  configRef:                   # ✅ implemented — the real config surface
    name: sample-gw-values
  infrastructure:
    labels: { team: platform } # ✅ implemented → commonLabels
    annotations:               # ✅ implemented → commonAnnotations
      prometheus.io/scrape: "true"
    image: ghcr.io/wso2/api-platform/gateway-controller:1.2.0    # ❌ ignored
    routerImage: ghcr.io/wso2/api-platform/gateway-runtime:1.2.0 # ❌ ignored
    replicas: 3                # ❌ ignored
    resources:                 # ❌ ignored
      requests: { cpu: "500m", memory: 1Gi }
    nodeSelector: { disktype: ssd }  # ❌ ignored
    tolerations: []            # ❌ ignored
    affinity: {}               # ❌ ignored
  controlPlane:
    host: "cp.example.svc.cluster.local:8443"   # ⚠️ registry-only, not deployed
    tls: { enabled: true }                      # ❌ ignored
    tokenSecretRef: { name: cp-token, key: token }  # ❌ ignored
  storage:
    type: sqlite               # ❌ ignored

Where each ignored field must be set today (via spec.configRef values.yaml):

CRD field (ignored) Equivalent configRef key
infrastructure.image gateway.controller.image.{repository,tag,pullPolicy}
infrastructure.routerImage gateway.gatewayRuntime.image.{repository,tag,pullPolicy}
infrastructure.replicas gateway.controller.deployment.replicaCount (+ gatewayRuntime)
infrastructure.resources gateway.controller.deployment.resources (+ gatewayRuntime)
infrastructure.nodeSelector/tolerations/affinity gateway.controller.deployment.{nodeSelector,tolerations,affinity} (+ gatewayRuntime)
storage.type gateway.config.controller.storage.type
controlPlane.host/token gateway.controller.controlPlane.{host,token}

spec.configRef is a superset — most of these are already settable there.

Every ignored field in the table above already has a configRef equivalent, so configRef fully covers them today, which makes the typed infrastructure.* / storage fields effectively redundant duplication of the chart's values surface. Two exceptions:

  • spec.controlPlane.tls maps to nothing in the gateway chart — control-plane TLS is implied by the host authority (HTTPS/WSS scheme + port); the chart's controller.controlPlane block has only host + token. This field has no backing at all and should simply be removed.
  • spec.apiSelector is operator-level API-selection logic, not a chart value — and it is already implemented.

Proposed resolution — pick one surface, don't leave both half-wired:

Option A — Implement the typed fields as the HIGHEST-priority override (recommended). Wire them in buildCRValuesOverlay → the chart keys above, and give the typed CRD fields precedence over configRef, so resolution becomes (highest wins):

typed spec.infrastructure fields (image, replicas, resources, ...)   <-- highest
  > spec.configRef ConfigMap
  > spec.infrastructure labels/annotations
  > operator default (GATEWAY_HELM_VALUES_FILE_PATH)
  > gateway-helm-chart built-in values                               <-- lowest

Rationale: typed fields are validated + discoverable, and a .spec change bumps metadata.generationreliable rollout (unlike a configRef edit, which is only picked up via the fragile ConfigMap-watch/hash path). This mirrors the params model other Gateway API operators use (kgateway GatewayParameters, Envoy Gateway EnvoyProxy). It is also backward-compatible for a GA CRD — additive wiring, no field removal. Behaviour-change caveat: a CR that already sets one of these (ignored today) would start taking effect and now win over its configRef — call this out in release notes.

Option B — Remove the redundant fields. Since configRef already covers them, drop infrastructure.{image,routerImage,replicas,resources,nodeSelector,tolerations,affinity} and storage from the CRD, leaving configRef as the single surface. Simpler, but the CRD is GA, so removal is a breaking schema change that needs a deprecation cycle.

Either way: remove spec.controlPlane.tls (no chart backing), and make the precedence explicit in each field's CRD description: and in the sample CR — e.g. annotate image as "Overrides gateway.controller.image in configRef and the operator default" (Option A) or "Deprecated: set via configRef" (Option B) — so kubectl explain / the YAML itself tells the user what the field does.

The same gap exists on the Gateway API path overlay (gateway_infrastructure_overlay.go also handles only labels/annotations/service).

Version

No response

Related Issue

No response

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with buildCRValuesOverlay in kubernetes/gateway-operator/internal/controller/apigateway_controller.go:757-779, then inspect gateway_infrastructure_overlay.go and the APIGateway CRD definitions and sample CR. Resolve whether typed fields should be wired with precedence or removed, verify the controlPlane and storage mappings against the chart values, and update field descriptions and the sample accordingly. Done means the chosen surface is explicit and no listed field is silently ignored.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, helm, kubernetes
Domain
backend-api-design, devops
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.