Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0fe861e
fix: set Cache-Control header before early returns (#1148)
jira-autofix[bot] Jul 27, 2026
e3671d5
fix: use OC bearer token for model discovery and inference in verify …
tgitelman Jul 27, 2026
9f385f0
fix: do not mark default AITenant bootstrapped when Terminating or no…
jira-autofix[bot] Jul 27, 2026
57f9ece
feat: secure allowedRoutes defaults for Gateway setup scripts (#1255)
somya-bhatnagar Jul 27, 2026
01f9373
fix: wait for gateway AuthPolicy Enforced before e2e API calls (#1265)
jland-redhat Jul 27, 2026
a04b06a
fix: use plain.selector for x-api-key identity source instead of plai…
jira-autofix[bot] Jul 28, 2026
1eb4b62
fix(RHOAIENG-79270): block false-positive AITenant readiness during M…
jira-autofix[bot] Jul 28, 2026
006206d
chore: add missing xks resources (#1271)
ahadas Jul 28, 2026
6ab9b68
docs: add v0.2.1 release notes and fix v0.2.0 version label (#1281)
jrhyness Jul 28, 2026
7f3c28f
fix: normalize empty INFRA_NAMESPACE to controller namespace in deplo…
jira-autofix[bot] Jul 28, 2026
ccb34c8
fix(RHOAIENG-79526): disable external model controller for non-defaul…
jira-autofix[bot] Jul 28, 2026
7158a87
fix(RHOAIENG-79535): disable IPP response api-translation by default …
jland-redhat Jul 29, 2026
49ca51c
fix: advertise gateway base url for externalmodel catalog (#1287)
jland-redhat Jul 29, 2026
a99fc3b
fix: increase chart range vector from [30m] to [2h] (#1242)
tgitelman Jul 29, 2026
d923742
fix(RHOAIENG-78602): auto-select xKS manifest overlay for maas-api (#…
tsisodia10 Jul 29, 2026
0506dd9
feat: replace user TextVariable with LokiLogQLVariable dropdown (#1243)
tgitelman Jul 29, 2026
9d2b0ba
fix: close default tenant bootstrap race (#1292)
dmytro-zaharnytskyi Jul 29, 2026
fc021d5
fix: apply payload-processing envoyfilter after kuadrant on tenant ga…
jland-redhat Jul 29, 2026
c31a8ed
fix(RHOAIENG-78601): set MAAS_PLATFORM_MANIFESTS in xKS overlay (#1290)
tsisodia10 Jul 30, 2026
adcb7ed
fix(RHOAIENG-79568): always verify gateway AuthPolicy enforcement bef…
jrhyness Jul 30, 2026
a5a5b5f
chore: promote main to stable (#1296)
ishitasequeira Jul 30, 2026
4eb7157
chore: promote stable to rhoai (#1299)
ishitasequeira Jul 30, 2026
a58b9ec
fix(RHOAIENG-76060): use groups_str path for captureGroup telemetry l…
somya-bhatnagar Jul 30, 2026
a8a8bd3
fix: unping Kuadrant 1.4.2 (#1078)
jland-redhat Jul 30, 2026
d303d83
docs: validate and fix multi-tenancy documentation accuracy (#1300)
EgorLu Jul 30, 2026
d7fd2e4
fix: add CEL has() guards to telemetry cost_center and organization_i…
liangwen12year Jul 30, 2026
9446f32
feat: add MaxConcurrentReconciles for subscription and authpolicy con…
liangwen12year Jul 31, 2026
4e99c99
chore: promote main to stable (#1304)
ishitasequeira Jul 31, 2026
7da3eb5
chore: promote stable to rhoai (#1305)
ishitasequeira Jul 31, 2026
68b9593
docs: document MaaSModelRef tenantRef field from PR #1250 (#1303)
jrhyness Jul 31, 2026
bd42904
fix(xKS): exclude PodMonitor and monitoring NetworkPolicy from xKS ov…
tsisodia10 Jul 31, 2026
928cf69
fix: add workloadSelector to MaaS EnvoyFilters for Istio 1.26 compati…
jland-redhat Jul 31, 2026
e39c1d5
chore: promote main to stable (#1307)
ishitasequeira Aug 1, 2026
cbbd2f6
chore: promote stable to rhoai (#1315)
jland-redhat Aug 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- maas-webhook-certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: maas-controller-webhook-server
spec:
commonName: maas-controller-webhook-service.$(NAMESPACE).svc
dnsNames:
- maas-controller-webhook-service.$(NAMESPACE).svc
- maas-controller-webhook-service.$(NAMESPACE).svc.cluster.local
duration: 8760h # 1 year
renewBefore: 720h # 30 days
issuerRef:
name: $(ISSUER_REF_NAME)
kind: $(ISSUER_REF_KIND)
group: $(ISSUER_REF_GROUP)
secretName: maas-controller-webhook-cert
122 changes: 122 additions & 0 deletions deployment/base/maas-controller/overlays/xks/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../crd
- ../../rbac
- ../../manager
- ../../webhook
- cert-manager/
# monitoring is excluded on xKS (OpenShift-specific ServiceMonitor/PodMonitor)

labels:
- pairs:
app.kubernetes.io/name: maas-controller
app.kubernetes.io/component: models-as-a-service
app.kubernetes.io/part-of: models-as-a-service

configMapGenerator:
- name: maas-parameters
envs:
- params.env

generatorOptions:
disableNameSuffixHash: true

replacements:
- source:
kind: ConfigMap
name: maas-parameters
fieldPath: data.maas-controller-image
targets:
- select:
kind: Deployment
name: maas-controller
fieldPaths:
- spec.template.spec.containers.[name=manager].image
- source:
kind: ConfigMap
name: maas-parameters
fieldPath: data.infrastructure-namespace
targets:
- select:
kind: Deployment
name: maas-controller
fieldPaths:
- spec.template.spec.containers.[name=manager].env.[name=INFRA_NAMESPACE].value
- source:
kind: ConfigMap
name: maas-parameters
fieldPath: data.gateway-namespace
targets:
- select:
kind: Deployment
name: maas-controller
fieldPaths:
- spec.template.spec.containers.[name=manager].env.[name=GATEWAY_NAMESPACE].value

patches:
# Remove OCP service-serving cert annotation (cert-manager handles TLS on xKS)
- target:
kind: Service
name: maas-controller-webhook-service
patch: |
- op: remove
path: /metadata/annotations/service.beta.openshift.io~1serving-cert-secret-name
- op: remove
path: /metadata/annotations/service.beta.openshift.io~1inject-cabundle

# Replace OCP CA injection with cert-manager CA injection on webhook
- target:
kind: ValidatingWebhookConfiguration
name: maas-validating-webhook-configuration
patch: |
- op: remove
path: /metadata/annotations/service.beta.openshift.io~1inject-cabundle
- op: add
path: /metadata/annotations/cert-manager.io~1inject-ca-from
value: "$(NAMESPACE)/maas-controller-webhook-server"

# Set platform manifests path so maas-controller uses xKS tenant overlay
- target:
kind: Deployment
name: maas-controller
patch: |
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: MAAS_PLATFORM_MANIFESTS
value: /maas-api/deploy/overlays/xks

vars:
- name: NAMESPACE
objref:
apiVersion: v1
kind: ConfigMap
name: maas-parameters
fieldref:
fieldpath: data.namespace
- name: ISSUER_REF_NAME
objref:
apiVersion: v1
kind: ConfigMap
name: maas-parameters
fieldref:
fieldpath: data.ISSUER_REF_NAME
- name: ISSUER_REF_KIND
objref:
apiVersion: v1
kind: ConfigMap
name: maas-parameters
fieldref:
fieldpath: data.ISSUER_REF_KIND
- name: ISSUER_REF_GROUP
objref:
apiVersion: v1
kind: ConfigMap
name: maas-parameters
fieldref:
fieldpath: data.ISSUER_REF_GROUP

configurations:
- params.yaml
11 changes: 11 additions & 0 deletions deployment/base/maas-controller/overlays/xks/params.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
maas-api-image=quay.io/opendatahub/maas-api:odh-stable
maas-controller-image=quay.io/opendatahub/maas-controller:odh-stable
payload-processing-image=quay.io/opendatahub/odh-ai-gateway-payload-processing:odh-stable
maas-api-key-cleanup-image=registry.redhat.io/ubi9/ubi-minimal:9.7
monitoring-namespace=
infrastructure-namespace=AUTO
gateway-namespace=redhat-ods-applications
namespace=redhat-ods-applications
ISSUER_REF_NAME=rhai-ca-issuer
ISSUER_REF_KIND=ClusterIssuer
ISSUER_REF_GROUP=cert-manager.io
13 changes: 13 additions & 0 deletions deployment/base/maas-controller/overlays/xks/params.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
varReference:
- path: spec/commonName
kind: Certificate
- path: spec/dnsNames
kind: Certificate
- path: spec/issuerRef/name
kind: Certificate
- path: spec/issuerRef/kind
kind: Certificate
- path: spec/issuerRef/group
kind: Certificate
- path: metadata/annotations
kind: ValidatingWebhookConfiguration
11 changes: 11 additions & 0 deletions deployment/base/maas-controller/rbac/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ rules:
- create
- delete
- get
- apiGroups:
- cert-manager.io
resources:
- certificates
verbs:
- create
- delete
- get
- list
- patch
- watch
- apiGroups:
- config.openshift.io
resources:
Expand Down
2 changes: 1 addition & 1 deletion deployment/base/networking/maas/maas-gateway-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
from: Same
tls:
certificateRefs:
- group: ''
Expand Down
18 changes: 14 additions & 4 deletions deployment/base/payload-processing/manager/envoy-filter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ metadata:
name: payload-processing
namespace: openshift-ingress
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: maas-default-gateway
# Must run AFTER Kuadrant's EnvoyFilter (default priority 0), which INSERT_BEFOREs
# envoy.filters.http.wasm relative to the router. Without a positive priority, istiod
# applies this resource first (same priority 0, older creationTimestamp) and the RHCL
# wasm anchors miss — ext_proc never enters the gateway filter chain (404 NR on
# body-routed /v1/*). Multi-tenant gateways are especially affected: their
# payload-processing-* EFs are often created before Kuadrant's per-gateway EF.
# ODH WasmPlugin anchors are unaffected: WasmPlugin is in the base chain before
# any EnvoyFilter patches.
# See: https://istio.io/latest/docs/reference/config/networking/envoy-filter/#EnvoyFilter
priority: 10
workloadSelector:
labels:
gateway.networking.k8s.io/gateway-name: maas-default-gateway
configPatches:
# Stage 1: must run BEFORE the WasmPlugin so auth sees X-Gateway-Model-Name.
- applyTo: HTTP_FILTER
Expand Down Expand Up @@ -70,6 +79,7 @@ spec:
message_timeout: 300s
# RHCL 1.4 injects auth via envoy.filters.http.wasm (no WasmPlugin CR). Only one anchor
# pair matches per cluster: WasmPlugin on ODH/community Kuadrant, wasm filter on RHCL 1.4.
# These patches require priority > Kuadrant's EF (see spec.priority above).
- applyTo: HTTP_FILTER
match:
context: GATEWAY
Expand Down
14 changes: 12 additions & 2 deletions deployment/base/payload-processing/manager/plugins-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ kind: ConfigMap
metadata:
name: payload-processing-plugins
namespace: openshift-ingress
# Do NOT set opendatahub.io/managed=false here: PostRender drops any resource that
# already carries that annotation, which would prevent first-time creation.
# The tenant reconciler stamps managed=false after bootstrap/migrate so later
# SSA leaves this ConfigMap alone (see ApplyRendered). Set managed=true on the
# live ConfigMap to opt back into continuous reconciler management.
data:
custom-pre-processing-ipp-config.yaml: |
apiVersion: llm-d.ai/v1alpha1
Expand Down Expand Up @@ -39,5 +44,10 @@ data:
- pluginRef: model-provider-resolver
- pluginRef: api-translation
- pluginRef: apikey-injection
response:
- pluginRef: api-translation
# Response api-translation is off by default so SSE streaming for
# internal/OpenAI-compatible models is not held by a response processor.
# Re-enable for providers that need response rewrite (e.g. Anthropic):
# response:
# - pluginRef: api-translation
# See docs/content/install/external-model-setup.md (IPP response translation).
response: []
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ spec:
spec:
display:
name: Token consumption chart
# [2h] matches the Loki dashboards' step for consistent cross-dashboard granularity.
description: >-
Tokens over time by model or subscription.
View by drives chart sum by (${view_by:raw}).
Expand Down Expand Up @@ -209,7 +210,7 @@ spec:
query: >-
round(sum by (${view_by:raw}) (increase(authorized_hits_total{user!="",
user=~"$user", subscription=~"$subscription",
model=~"$model"}[30m])))
model=~"$model"}[2h])))
tokenConsumptionByUser:
kind: Panel
spec:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@ metadata:
app.kubernetes.io/part-of: maas-observability
app.kubernetes.io/managed-by: maas-controller
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: maas-default-gateway
workloadSelector:
labels:
gateway.networking.k8s.io/gateway-name: maas-default-gateway
configPatches:

# ── Cluster: gRPC endpoint to OTel Collector ──────────────────────────
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Admin usage dashboard — queries Loki structured logs via LogQL.
# Uses $__range to bind LogQL windows to the native time picker.
# LokiLabelValuesVariable for model/subscription dropdowns (COO 1.5+).
# User filter uses TextVariable (regex input) to avoid Loki cardinality issues
# from indexing high-cardinality user_id as a label. Admins enter regex patterns.
# All three dropdowns (user, subscription, model) follow the dashboard time
# picker. User filter uses LokiLogQLVariable with [$__range] — auto-populates
# from structured metadata via count by (user_id), bypassing /label/values
# (which requires stream labels). Subscription/model use LokiLabelValuesVariable.
# customAllValue: ".*" on ListVariables ensures "All" matches entries with
# absent labels (e.g. subscription when capturing is disabled). Do not remove.
apiVersion: perses.dev/v1alpha1
Expand All @@ -21,13 +22,24 @@ spec:
rate limiting, and per-user breakdown across all users and subscriptions.
duration: 1h
variables:
- kind: TextVariable
- kind: ListVariable
spec:
name: user
display:
name: "User (regex)"
description: "Filter by user ID. Use regex: 'user-1' (single), 'user-1|user-2' (multiple), '.*' (all)"
defaultValue: ".*"
name: "User"
description: "Filter by user. Populated from the selected time range."
allowMultiple: true
allowAllValue: true
customAllValue: ".*"
defaultValue: "$__all"
plugin:
kind: LokiLogQLVariable
spec:
datasource:
kind: LokiDatasource
name: usage-logs-all
expr: 'count by (user_id) (count_over_time({service_name="models-as-a-service"} | user_id!="" | user_id!="-" | keep user_id [$__range]))'
labelName: user_id
- kind: ListVariable
spec:
name: subscription
Expand Down Expand Up @@ -240,11 +252,11 @@ spec:
spec:
display:
name: "Token consumption chart"
# [2h] is the minimal stable step. Loki split_queries_by_interval is 30m; 1h still produces
# gaps at chunk boundaries. 2h is the lowest value that returns consistent results.
description: >-
Tokens from successful requests (2xx) over time by model or subscription.
**View by** drives chart ``sum by (${view_by:raw})``. Table uses hardcoded ``sum by (model, subscription)``.
LogQL ``[30m]`` is the range window for ``sum_over_time`` (Perses time-series step).
Visual: OpenShift Perses pattern — ``line`` + ``areaOpacity: 1`` + ``stack: all``.
**View by** drives the chart grouping.
plugin:
kind: TimeSeriesChart
spec:
Expand Down Expand Up @@ -277,7 +289,7 @@ spec:
sum by (${view_by:raw}) (sum_over_time({service_name="models-as-a-service",
subscription=~"$subscription", model=~"$model", response_type="hit"}
| user_id=~"$user"
| unwrap tokens_total [30m]))
| unwrap tokens_total [2h]))

tokenConsumptionTable:
kind: Panel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ spec:
spec:
display:
name: "Token consumption chart"
# [2h] is the minimal stable step. Loki split_queries_by_interval is 30m; 1h still produces
# gaps at chunk boundaries. 2h is the lowest value that returns consistent results.
description: >-
Tokens from successful requests (2xx) over time by model or subscription.
plugin:
Expand Down Expand Up @@ -237,7 +239,7 @@ spec:
query: >-
sum by (${view_by:raw}) (sum_over_time({service_name="models-as-a-service",
subscription=~"$subscription", model=~"$model", response_type="hit"}
| unwrap tokens_total [30m]))
| unwrap tokens_total [2h]))

tokenConsumptionTable:
kind: Panel
Expand Down
Loading
Loading