mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-16 04:29:31 +00:00
feat(helm): read database and Redis host or URL from a Kubernetes Secret (#46410)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
9f6379223c
commit
1999751bae
5 changed files with 721 additions and 13 deletions
|
|
@ -22,12 +22,14 @@ Reminders:
|
|||
- database.writer.{host,port,dbname} (writer connection pieces)
|
||||
- database.writer.passwordSecret.{name,usernameKey,passwordKey}
|
||||
(Secret holding the writer DB username + password)
|
||||
- database.writer.passwordSecret.{hostKey,urlKey} (optional, read writer host or full URL from that Secret)
|
||||
- database.writer.useIAMAuth: true (optional — chart sets IAM_TOKEN_DB_AUTH=true and
|
||||
omits DATABASE_PASSWORD / DATABASE_URL so the proxy
|
||||
mints the URL from an IAM token at startup)
|
||||
- database.reader.host (optional — enables read-replica routing; reader
|
||||
.passwordSecret.name is required when set, unless
|
||||
.useIAMAuth is true)
|
||||
- database.reader.host / database.reader.passwordSecret.{hostKey,urlKey}
|
||||
(optional, enables read-replica routing. The Secret
|
||||
name is required for hostKey, urlKey, and for host
|
||||
with password auth)
|
||||
- database.reader.useIAMAuth: true (optional, requires database.writer.useIAMAuth: true —
|
||||
chart emits DATABASE_*_READ_REPLICA env vars and
|
||||
omits DATABASE_PASSWORD_READ_REPLICA /
|
||||
|
|
@ -35,6 +37,8 @@ Reminders:
|
|||
reader URL from an IAM token at startup)
|
||||
- redis.passwordSecret.name (optional — set when redis.host is provided and the
|
||||
cache requires auth)
|
||||
- redis.passwordSecret.{hostKey,urlKey} (optional, read Redis host or full URL from that Secret)
|
||||
(the Secret name is required when either key is set)
|
||||
- redis.cluster: true (optional — chart sets REDIS_CLUSTER_NODES from
|
||||
redis.host / redis.port so the proxy's Cache()
|
||||
constructs a RedisClusterCache; the cluster client
|
||||
|
|
|
|||
|
|
@ -202,7 +202,9 @@ the chart context (needed for .Values), `component` selects which component's
|
|||
Sensitive values (master key, DB username + password, Redis password) come
|
||||
only from referenced Secrets; the chart never accepts inline values for them.
|
||||
|
||||
The chart never assembles DATABASE_URL itself. It emits only the discrete
|
||||
The chart never assembles DATABASE_URL itself. When
|
||||
database.writer.passwordSecret.urlKey is set, the chart passes the operator's
|
||||
URL through from the Secret. Otherwise it emits only the discrete
|
||||
DATABASE_HOST/PORT/USER/NAME/SCHEMA (+ DATABASE_PASSWORD for password auth)
|
||||
vars; the proxy's entrypoint (DatabaseURLSettings in
|
||||
litellm/proxy/db/db_url_settings.py) builds the URL from them and
|
||||
|
|
@ -218,11 +220,11 @@ token instead of a static password. `database.writer.useAzureEntraAuth: true`
|
|||
does the same with AZURE_POSTGRESQL_AUTH=true and a Microsoft Entra ID token,
|
||||
for Azure Database for PostgreSQL. The two are mutually exclusive.
|
||||
|
||||
The read replica is opt-in via `database.reader.host`. The chart emits
|
||||
DATABASE_HOST_READ_REPLICA / DATABASE_PORT_READ_REPLICA /
|
||||
DATABASE_NAME_READ_REPLICA (+ DATABASE_SCHEMA_READ_REPLICA) for both auth
|
||||
modes, plus DATABASE_USER_READ_REPLICA / DATABASE_PASSWORD_READ_REPLICA for
|
||||
password auth. When `database.reader.useIAMAuth: true` (or
|
||||
The read replica is opt-in via `database.reader.host`, `hostKey`, or `urlKey`.
|
||||
The chart emits DATABASE_URL_READ_REPLICA alone for urlKey, or discrete
|
||||
DATABASE_*_READ_REPLICA vars for host and hostKey configurations, plus
|
||||
DATABASE_USER_READ_REPLICA / DATABASE_PASSWORD_READ_REPLICA for password auth.
|
||||
When `database.reader.useIAMAuth: true` (or
|
||||
`database.reader.useAzureEntraAuth: true`) it omits
|
||||
DATABASE_PASSWORD_READ_REPLICA and the entrypoint mints the reader URL the
|
||||
same way. Reader token auth only takes effect when the writer uses the same
|
||||
|
|
@ -242,8 +244,36 @@ IAM_TOKEN_DB_AUTH / AZURE_POSTGRESQL_AUTH toggle that only the writer sets.
|
|||
value: {{ $component.logLevel | quote }}
|
||||
{{- end }}
|
||||
{{- with $root.Values.database.writer }}
|
||||
{{- $hostKey := .passwordSecret.hostKey }}
|
||||
{{- $urlKey := .passwordSecret.urlKey }}
|
||||
{{- if and .host $hostKey }}
|
||||
{{- fail "database.writer.host and database.writer.passwordSecret.hostKey cannot both be set" }}
|
||||
{{- end }}
|
||||
{{- if and $urlKey (or .host $hostKey .dbname .schema .sslMode .sslRootCert .useIAMAuth .useAzureEntraAuth) }}
|
||||
{{- fail "database.writer.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, sslMode, sslRootCert, useIAMAuth, or useAzureEntraAuth" }}
|
||||
{{- end }}
|
||||
{{- if and (not .host) (not $hostKey) (not $urlKey) }}
|
||||
{{- fail "one of database.writer.host, database.writer.passwordSecret.hostKey, or database.writer.passwordSecret.urlKey is required" }}
|
||||
{{- end }}
|
||||
{{- if and (or $hostKey $urlKey) (not .passwordSecret.name) }}
|
||||
{{- fail "database.writer.passwordSecret.name is required when hostKey or urlKey is set" }}
|
||||
{{- end }}
|
||||
{{- if $urlKey }}
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .passwordSecret.name | quote }}
|
||||
key: {{ $urlKey | quote }}
|
||||
{{- else }}
|
||||
- name: DATABASE_HOST
|
||||
value: {{ required "database.writer.host is required" .host | quote }}
|
||||
{{- if $hostKey }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .passwordSecret.name | quote }}
|
||||
key: {{ $hostKey | quote }}
|
||||
{{- else }}
|
||||
value: {{ .host | quote }}
|
||||
{{- end }}
|
||||
- name: DATABASE_PORT
|
||||
value: {{ .port | default 5432 | quote }}
|
||||
- name: DATABASE_USER
|
||||
|
|
@ -282,8 +312,29 @@ IAM_TOKEN_DB_AUTH / AZURE_POSTGRESQL_AUTH toggle that only the writer sets.
|
|||
key: {{ .passwordSecret.passwordKey | default "password" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with $root.Values.database.reader }}
|
||||
{{- if .host }}
|
||||
{{- $readerSecret := .passwordSecret | default dict }}
|
||||
{{- $hostKey := $readerSecret.hostKey }}
|
||||
{{- $urlKey := $readerSecret.urlKey }}
|
||||
{{- $readerEnabled := or .host $hostKey $urlKey }}
|
||||
{{- if and .host $hostKey }}
|
||||
{{- fail "database.reader.host and database.reader.passwordSecret.hostKey cannot both be set" }}
|
||||
{{- end }}
|
||||
{{- if and $urlKey (or .host $hostKey .dbname .schema .useIAMAuth .useAzureEntraAuth) }}
|
||||
{{- fail "database.reader.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, useIAMAuth, or useAzureEntraAuth" }}
|
||||
{{- end }}
|
||||
{{- if and (or $hostKey $urlKey) (not $readerSecret.name) }}
|
||||
{{- fail "database.reader.passwordSecret.name is required when hostKey or urlKey is set" }}
|
||||
{{- end }}
|
||||
{{- if $readerEnabled }}
|
||||
{{- if $urlKey }}
|
||||
- name: DATABASE_URL_READ_REPLICA
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $readerSecret.name | quote }}
|
||||
key: {{ $urlKey | quote }}
|
||||
{{- else }}
|
||||
{{- if and .useIAMAuth (not $root.Values.database.writer.useIAMAuth) }}
|
||||
{{- fail "database.reader.useIAMAuth requires database.writer.useIAMAuth: true (the proxy gates IAM URL minting on IAM_TOKEN_DB_AUTH, which is only set by the writer)" }}
|
||||
{{- end }}
|
||||
|
|
@ -291,11 +342,18 @@ IAM_TOKEN_DB_AUTH / AZURE_POSTGRESQL_AUTH toggle that only the writer sets.
|
|||
{{- fail "database.reader.useAzureEntraAuth requires database.writer.useAzureEntraAuth: true (the proxy gates Entra URL minting on AZURE_POSTGRESQL_AUTH, which is only set by the writer)" }}
|
||||
{{- end }}
|
||||
- name: DATABASE_HOST_READ_REPLICA
|
||||
{{- if $hostKey }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $readerSecret.name | quote }}
|
||||
key: {{ $hostKey | quote }}
|
||||
{{- else }}
|
||||
value: {{ .host | quote }}
|
||||
{{- end }}
|
||||
- name: DATABASE_PORT_READ_REPLICA
|
||||
value: {{ .port | default 5432 | quote }}
|
||||
- name: DATABASE_NAME_READ_REPLICA
|
||||
value: {{ required "database.reader.dbname is required when database.reader.host is set" .dbname | quote }}
|
||||
value: {{ required "database.reader.dbname is required when database.reader.host, hostKey, or urlKey is set" .dbname | quote }}
|
||||
{{- if .schema }}
|
||||
- name: DATABASE_SCHEMA_READ_REPLICA
|
||||
value: {{ .schema | quote }}
|
||||
|
|
@ -325,6 +383,7 @@ IAM_TOKEN_DB_AUTH / AZURE_POSTGRESQL_AUTH toggle that only the writer sets.
|
|||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{/*
|
||||
The migrations Job (helm.sh/hook: pre-upgrade) is the single owner of
|
||||
`prisma migrate deploy`. Without this, every gateway/backend pod also runs
|
||||
|
|
@ -341,9 +400,34 @@ harmless no-op for the Job and authoritative for the app pods.
|
|||
tracking, pod lock manager) via its REDIS_* env fallback. An explicit
|
||||
`general_settings.coordination_redis` block in proxy_config takes
|
||||
precedence over anything emitted here. */}}
|
||||
{{- if $root.Values.redis.host }}
|
||||
{{- $redisSecret := $root.Values.redis.passwordSecret | default dict }}
|
||||
{{- $hostKey := $redisSecret.hostKey }}
|
||||
{{- $urlKey := $redisSecret.urlKey }}
|
||||
{{- if and $root.Values.redis.host $hostKey }}
|
||||
{{- fail "redis.host and redis.passwordSecret.hostKey cannot both be set" }}
|
||||
{{- end }}
|
||||
{{- if and $urlKey (or $root.Values.redis.host $hostKey $root.Values.redis.cluster) }}
|
||||
{{- fail "redis.passwordSecret.urlKey cannot be combined with host, hostKey, or cluster" }}
|
||||
{{- end }}
|
||||
{{- if and (or $hostKey $urlKey) (not $redisSecret.name) }}
|
||||
{{- fail "redis.passwordSecret.name is required when hostKey or urlKey is set" }}
|
||||
{{- end }}
|
||||
{{- if $urlKey }}
|
||||
- name: REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $redisSecret.name | quote }}
|
||||
key: {{ $urlKey | quote }}
|
||||
{{- else if or $root.Values.redis.host $hostKey }}
|
||||
- name: REDIS_HOST
|
||||
{{- if $hostKey }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $redisSecret.name | quote }}
|
||||
key: {{ $hostKey | quote }}
|
||||
{{- else }}
|
||||
value: {{ $root.Values.redis.host | quote }}
|
||||
{{- end }}
|
||||
- name: REDIS_PORT
|
||||
value: {{ $root.Values.redis.port | quote }}
|
||||
{{- if $root.Values.redis.passwordSecret.name }}
|
||||
|
|
@ -360,7 +444,11 @@ harmless no-op for the Job and authoritative for the app pods.
|
|||
configured endpoint; the cluster client discovers the remaining nodes from
|
||||
CLUSTER SLOTS at startup. */}}
|
||||
- name: REDIS_CLUSTER_NODES
|
||||
{{- if $hostKey }}
|
||||
value: {{ printf "[{\"host\":\"$(REDIS_HOST)\",\"port\":%v}]" (int $root.Values.redis.port) | quote }}
|
||||
{{- else }}
|
||||
value: {{ printf "[{\"host\":%q,\"port\":%v}]" $root.Values.redis.host (int $root.Values.redis.port) | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with $component.extraEnv }}
|
||||
|
|
|
|||
|
|
@ -191,3 +191,400 @@ tests:
|
|||
content:
|
||||
name: DATABASE_PASSWORD_READ_REPLICA
|
||||
any: true
|
||||
|
||||
- it: writer hostKey reads the host from the Secret and supports IAM auth
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.passwordSecret.hostKey: hostname
|
||||
database.writer.useIAMAuth: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: hostname
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: IAM_TOKEN_DB_AUTH
|
||||
value: "true"
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD
|
||||
any: true
|
||||
|
||||
- it: writer urlKey supplies only DATABASE_URL to each database client container and keeps pool env
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.dbname: ""
|
||||
database.writer.schema: ""
|
||||
database.writer.sslMode: ""
|
||||
database.writer.sslRootCert: ""
|
||||
database.writer.passwordSecret.urlKey: connection-url
|
||||
database.connectionPool.enabled: true
|
||||
gateway.collector.enabled: true
|
||||
gateway.metricsServer.enabled: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: connection-url
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_HOST
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PORT
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_USER
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_NAME
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_SCHEMA
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_SSLMODE
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_SSLROOTCERT
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notExists:
|
||||
path: >-
|
||||
spec.template.spec.containers[0].env[?(@.name == "DATABASE_HOST" ||
|
||||
@.name == "DATABASE_PORT" || @.name == "DATABASE_USER" ||
|
||||
@.name == "DATABASE_NAME" || @.name == "DATABASE_SCHEMA" ||
|
||||
@.name == "DATABASE_SSLMODE" || @.name == "DATABASE_SSLROOTCERT" ||
|
||||
@.name == "DATABASE_PASSWORD")]
|
||||
template: gateway/deployment.yaml
|
||||
- notExists:
|
||||
path: >-
|
||||
spec.template.spec.containers[2].env[?(@.name == "DATABASE_HOST" ||
|
||||
@.name == "DATABASE_PORT" || @.name == "DATABASE_USER" ||
|
||||
@.name == "DATABASE_NAME" || @.name == "DATABASE_SCHEMA" ||
|
||||
@.name == "DATABASE_SSLMODE" || @.name == "DATABASE_SSLROOTCERT" ||
|
||||
@.name == "DATABASE_PASSWORD")]
|
||||
template: gateway/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: LITELLM_PGBOUNCER_ENABLED
|
||||
value: "true"
|
||||
template: gateway/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[2].env
|
||||
content:
|
||||
name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: connection-url
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[2].env
|
||||
content:
|
||||
name: DATABASE_USER
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[2].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD
|
||||
any: true
|
||||
template: gateway/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[2].env
|
||||
content:
|
||||
name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: connection-url
|
||||
template: gateway/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[2].env
|
||||
content:
|
||||
name: LITELLM_PGBOUNCER_ENABLED
|
||||
value: "true"
|
||||
template: gateway/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: connection-url
|
||||
template: backend/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_USER
|
||||
any: true
|
||||
template: backend/deployment.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD
|
||||
any: true
|
||||
template: backend/deployment.yaml
|
||||
- notExists:
|
||||
path: >-
|
||||
spec.template.spec.containers[0].env[?(@.name == "DATABASE_HOST" ||
|
||||
@.name == "DATABASE_PORT" || @.name == "DATABASE_USER" ||
|
||||
@.name == "DATABASE_NAME" || @.name == "DATABASE_SCHEMA" ||
|
||||
@.name == "DATABASE_SSLMODE" || @.name == "DATABASE_SSLROOTCERT" ||
|
||||
@.name == "DATABASE_PASSWORD")]
|
||||
template: backend/deployment.yaml
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-writer-secret
|
||||
key: connection-url
|
||||
template: migrations-job.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_USER
|
||||
any: true
|
||||
template: migrations-job.yaml
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD
|
||||
any: true
|
||||
template: migrations-job.yaml
|
||||
- notExists:
|
||||
path: >-
|
||||
spec.template.spec.containers[0].env[?(@.name == "DATABASE_HOST" ||
|
||||
@.name == "DATABASE_PORT" || @.name == "DATABASE_USER" ||
|
||||
@.name == "DATABASE_NAME" || @.name == "DATABASE_SCHEMA" ||
|
||||
@.name == "DATABASE_SSLMODE" || @.name == "DATABASE_SSLROOTCERT" ||
|
||||
@.name == "DATABASE_PASSWORD")]
|
||||
template: migrations-job.yaml
|
||||
|
||||
- it: writer rejects host together with hostKey
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.passwordSecret.hostKey: hostname
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.writer.host and database.writer.passwordSecret.hostKey cannot both be set"
|
||||
|
||||
- it: writer rejects urlKey with discrete connection settings
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.passwordSecret.urlKey: connection-url
|
||||
database.writer.schema: public
|
||||
database.writer.sslMode: require
|
||||
database.writer.sslRootCert: /etc/ssl/ca.crt
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.writer.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, sslMode, sslRootCert, useIAMAuth, or useAzureEntraAuth"
|
||||
|
||||
- it: writer rejects urlKey with IAM auth
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.dbname: ""
|
||||
database.writer.passwordSecret.urlKey: connection-url
|
||||
database.writer.useIAMAuth: true
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.writer.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, sslMode, sslRootCert, useIAMAuth, or useAzureEntraAuth"
|
||||
|
||||
- it: writer rejects urlKey with Entra auth
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.dbname: ""
|
||||
database.writer.passwordSecret.urlKey: connection-url
|
||||
database.writer.useAzureEntraAuth: true
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.writer.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, sslMode, sslRootCert, useIAMAuth, or useAzureEntraAuth"
|
||||
|
||||
- it: writer requires an endpoint
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "one of database.writer.host, database.writer.passwordSecret.hostKey, or database.writer.passwordSecret.urlKey is required"
|
||||
|
||||
- it: writer hostKey requires a Secret name
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.host: ""
|
||||
database.writer.passwordSecret.hostKey: hostname
|
||||
database.writer.passwordSecret.name: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.writer.passwordSecret.name is required when hostKey or urlKey is set"
|
||||
|
||||
- it: reader renders without replica env vars when passwordSecret is null
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.reader.passwordSecret: null
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_HOST_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_URL_READ_REPLICA
|
||||
any: true
|
||||
|
||||
- it: reader hostKey enables replica routing and reads its host from the Secret
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.useIAMAuth: true
|
||||
database.reader.passwordSecret.hostKey: hostname
|
||||
database.reader.dbname: litellm
|
||||
database.reader.useIAMAuth: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_HOST_READ_REPLICA
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-reader-secret
|
||||
key: hostname
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_NAME_READ_REPLICA
|
||||
value: litellm
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: IAM_TOKEN_DB_AUTH
|
||||
value: "true"
|
||||
|
||||
- it: reader urlKey emits only the replica URL
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.reader.passwordSecret.urlKey: connection-url
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_URL_READ_REPLICA
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: litellm-reader-secret
|
||||
key: connection-url
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_HOST_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PORT_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_USER_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_PASSWORD_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_NAME_READ_REPLICA
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: DATABASE_SCHEMA_READ_REPLICA
|
||||
any: true
|
||||
|
||||
- it: reader rejects host together with hostKey
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.reader.host: reader.example.com
|
||||
database.reader.passwordSecret.hostKey: hostname
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.reader.host and database.reader.passwordSecret.hostKey cannot both be set"
|
||||
|
||||
- it: reader rejects urlKey with discrete connection settings
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.reader.passwordSecret.urlKey: connection-url
|
||||
database.reader.dbname: litellm
|
||||
database.reader.schema: public
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.reader.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, useIAMAuth, or useAzureEntraAuth"
|
||||
|
||||
- it: reader rejects urlKey with token auth
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.writer.useIAMAuth: true
|
||||
database.reader.passwordSecret.urlKey: connection-url
|
||||
database.reader.useIAMAuth: true
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.reader.passwordSecret.urlKey cannot be combined with host, hostKey, dbname, schema, useIAMAuth, or useAzureEntraAuth"
|
||||
|
||||
- it: reader urlKey requires a Secret name
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
database.reader.passwordSecret.urlKey: connection-url
|
||||
database.reader.passwordSecret.name: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "database.reader.passwordSecret.name is required when hostKey or urlKey is set"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,27 @@ tests:
|
|||
name: REDIS_CLUSTER_NODES
|
||||
any: true
|
||||
|
||||
- it: gateway renders without redis env vars when passwordSecret is null
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret: null
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_HOST
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_URL
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PASSWORD
|
||||
any: true
|
||||
|
||||
- it: gateway emits host, port and password when redis is configured
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
|
|
@ -68,6 +89,27 @@ tests:
|
|||
name: redis-secret
|
||||
key: redis-password
|
||||
|
||||
- it: backend renders without redis env vars when passwordSecret is null
|
||||
template: backend/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret: null
|
||||
asserts:
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_HOST
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_URL
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PASSWORD
|
||||
any: true
|
||||
|
||||
- it: gateway omits REDIS_PASSWORD for an auth-less redis
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
|
|
@ -107,3 +149,174 @@ tests:
|
|||
content:
|
||||
name: REDIS_CLUSTER_NODES
|
||||
any: true
|
||||
|
||||
- it: gateway gets redis host from hostKey and keeps port and password
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.host: ""
|
||||
redis.port: 6380
|
||||
redis.passwordSecret.name: redis-secret
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
redis.passwordSecret.passwordKey: redis-password
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secret
|
||||
key: hostname
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PORT
|
||||
value: "6380"
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secret
|
||||
key: redis-password
|
||||
|
||||
- it: backend gets redis host from hostKey with the same coordination env
|
||||
template: backend/deployment.yaml
|
||||
set:
|
||||
redis.host: ""
|
||||
redis.passwordSecret.name: redis-secret
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secret
|
||||
key: hostname
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PORT
|
||||
value: "6379"
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secret
|
||||
key: password
|
||||
|
||||
- it: gateway expands the redis cluster seed from hostKey at runtime
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.host: ""
|
||||
redis.passwordSecret.name: redis-secret
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
redis.cluster: true
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_CLUSTER_NODES
|
||||
value: '[{"host":"$(REDIS_HOST)","port":6379}]'
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].env[8].name
|
||||
value: REDIS_HOST
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].env[11].name
|
||||
value: REDIS_CLUSTER_NODES
|
||||
|
||||
- it: gateway gets REDIS_URL from urlKey without discrete Redis env
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret.name: redis-secret
|
||||
redis.passwordSecret.urlKey: connection-url
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secret
|
||||
key: connection-url
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_HOST
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PORT
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_PASSWORD
|
||||
any: true
|
||||
- notContains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: REDIS_CLUSTER_NODES
|
||||
any: true
|
||||
|
||||
- it: redis rejects host together with hostKey
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.host: redis.example.com
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
redis.passwordSecret.name: redis-secret
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.host and redis.passwordSecret.hostKey cannot both be set"
|
||||
|
||||
- it: redis urlKey rejects host
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.host: redis.example.com
|
||||
redis.passwordSecret.urlKey: connection-url
|
||||
redis.passwordSecret.name: redis-secret
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.passwordSecret.urlKey cannot be combined with host, hostKey, or cluster"
|
||||
|
||||
- it: redis urlKey rejects hostKey
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
redis.passwordSecret.urlKey: connection-url
|
||||
redis.passwordSecret.name: redis-secret
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.passwordSecret.urlKey cannot be combined with host, hostKey, or cluster"
|
||||
|
||||
- it: redis urlKey rejects cluster mode
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.cluster: true
|
||||
redis.passwordSecret.urlKey: connection-url
|
||||
redis.passwordSecret.name: redis-secret
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.passwordSecret.urlKey cannot be combined with host, hostKey, or cluster"
|
||||
|
||||
- it: redis hostKey requires a Secret name
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret.hostKey: hostname
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.passwordSecret.name is required when hostKey or urlKey is set"
|
||||
|
||||
- it: redis urlKey requires a Secret name
|
||||
template: gateway/deployment.yaml
|
||||
set:
|
||||
redis.passwordSecret.urlKey: connection-url
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "redis.passwordSecret.name is required when hostKey or urlKey is set"
|
||||
|
|
|
|||
|
|
@ -208,6 +208,8 @@ database:
|
|||
name: litellm-writer-secret
|
||||
usernameKey: username
|
||||
passwordKey: password
|
||||
hostKey: "" # Secret key containing the writer database host
|
||||
urlKey: "" # Secret key containing the complete writer database URL
|
||||
# libpq sslmode / sslrootcert applied to the writer and reader URLs (Prisma and the
|
||||
# in-container PgBouncer); e.g. verify-full with /etc/ssl/certs/ca-certificates.crt for AWS RDS.
|
||||
# sslRootCert on its own implies sslMode verify-full
|
||||
|
|
@ -229,6 +231,8 @@ database:
|
|||
name: litellm-reader-secret
|
||||
usernameKey: username
|
||||
passwordKey: password
|
||||
hostKey: "" # Secret key containing the reader database host
|
||||
urlKey: "" # Secret key containing the complete reader database URL
|
||||
|
||||
# In-container connection pool (PgBouncer, transaction mode) shared by every
|
||||
# gateway worker in the pod. Without it each of the `gateway.numWorkers`
|
||||
|
|
@ -274,6 +278,8 @@ redis:
|
|||
passwordSecret:
|
||||
name: "" # Leave empty for auth-less Redis
|
||||
passwordKey: password
|
||||
hostKey: "" # Secret key containing the Redis host
|
||||
urlKey: "" # Secret key containing the complete Redis URL
|
||||
|
||||
# ---------- gateway (LLM data plane) ----------
|
||||
gateway:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue