diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e938378..62ca2cc 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -10,5 +10,6 @@ "charts/nodejs": "0.3.2", "charts/pachyderm": "0.3.0", "charts/postgrest": "0.7.0", - "charts/openldap": "1.3.0" + "charts/openldap": "1.3.0", + "charts/xapi-lrs": "0.1.0" } diff --git a/charts/xapi-lrs/.helmignore b/charts/xapi-lrs/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/xapi-lrs/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/xapi-lrs/Chart.yaml b/charts/xapi-lrs/Chart.yaml new file mode 100644 index 0000000..dd09597 --- /dev/null +++ b/charts/xapi-lrs/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: xapi-lrs +description: xapi-lrs Learning Record Store helm chart +type: application +home: https://github.com/pelotech/xapi-lrs +sources: + - https://github.com/pelotech/xapi-lrs +keywords: + - xapi + - lrs + - learning-record-store + - tin-can + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.7.1" diff --git a/charts/xapi-lrs/README.md b/charts/xapi-lrs/README.md new file mode 100644 index 0000000..ef8097e --- /dev/null +++ b/charts/xapi-lrs/README.md @@ -0,0 +1,131 @@ +# xapi-lrs + +### version: 0.1.0 + +![AppVersion: 0.7.1](https://img.shields.io/badge/AppVersion-0.7.1-informational?style=flat-square) + +xapi-lrs Learning Record Store helm chart + +**Homepage:** + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| auth.adminPassword | string | `""` | | +| auth.adminUser | string | `"admin"` | | +| auth.apiKey | string | `""` | | +| auth.apiSecret | string | `""` | | +| auth.existingSecret | string | `""` | | +| auth.existingSecretKeys.adminPassword | string | `"admin-password"` | | +| auth.existingSecretKeys.apiSecret | string | `"api-secret"` | | +| auth.existingSecretKeys.migrationPostgresqlPassword | string | `"migration-postgresql-password"` | | +| auth.existingSecretKeys.postgresqlPassword | string | `"postgresql-password"` | | +| auth.existingSecretKeys.sessionSecret | string | `"session-secret"` | | +| auth.sessionSecret | string | `""` | | +| automountServiceAccountToken | bool | `false` | | +| commonAnnotations | object | `{}` | | +| containerPorts.admin | int | `8091` | | +| containerPorts.http | int | `8081` | | +| cors.enabled | bool | `false` | | +| cors.origin | string | `""` | | +| database.driver | string | `"pg"` | | +| database.postgresql.database | string | `"xapi_lrs"` | | +| database.postgresql.host | string | `"postgres"` | | +| database.postgresql.password | string | `""` | | +| database.postgresql.port | int | `5432` | | +| database.postgresql.url | string | `""` | | +| database.postgresql.user | string | `"xapi_lrs"` | | +| enableServiceLinks | bool | `false` | | +| extraEnvVars | list | `[]` | | +| extraEnvVarsCM | string | `""` | | +| extraEnvVarsSecret | string | `""` | | +| fullnameOverride | string | `""` | | +| gateway.enabled | bool | `false` | | +| gateway.hostname | string | `""` | | +| gateway.httpRoute.annotations | object | `{}` | | +| gateway.httpRoute.extraHostnames | list | `[]` | | +| gateway.httpRoute.gatewayName | string | `""` | | +| gateway.httpRoute.gatewayNamespace | string | `""` | | +| gateway.httpRoute.path | string | `"/"` | | +| gateway.httpRoute.pathType | string | `"PathPrefix"` | | +| gateway.httpRoute.port | string | `""` | | +| gateway.httpRoute.rules | list | `[]` | | +| gateway.httpRoute.sectionName | string | `""` | | +| gateway.listenerSet.annotations | object | `{}` | | +| gateway.listenerSet.enabled | bool | `false` | | +| gateway.listenerSet.gatewayName | string | `""` | | +| gateway.listenerSet.gatewayNamespace | string | `""` | | +| gateway.listenerSet.https.enabled | bool | `true` | | +| gateway.listenerSet.https.secretName | string | `""` | | +| gateway.listenerSet.listeners | list | `[]` | | +| image.digest | string | `"sha256:5edc504b19375c5b19e7e3289308d227fb6b219f6226488d1360ff0c8e5d87ac"` | | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.pullSecrets | list | `[]` | | +| image.registry | string | `"ghcr.io"` | | +| image.repository | string | `"pelotech/xapi-lrs"` | | +| image.tag | string | `"0.7.1"` | | +| ingress.annotations | object | `{}` | | +| ingress.enabled | bool | `false` | | +| ingress.extraHosts | list | `[]` | | +| ingress.extraPaths | list | `[]` | | +| ingress.extraTls | list | `[]` | | +| ingress.hostname | string | `"xapi-lrs.local"` | | +| ingress.ingressClassName | string | `""` | | +| ingress.path | string | `"/"` | | +| ingress.pathType | string | `"ImplementationSpecific"` | | +| ingress.tls | bool | `false` | | +| livenessProbe.httpGet.path | string | `"/healthz"` | | +| livenessProbe.httpGet.port | string | `"admin"` | | +| livenessProbe.initialDelaySeconds | int | `10` | | +| livenessProbe.periodSeconds | int | `10` | | +| logLevel | string | `"info"` | | +| metrics.serviceMonitor.enabled | bool | `false` | | +| metrics.serviceMonitor.honorLabels | bool | `false` | | +| metrics.serviceMonitor.interval | string | `"30s"` | | +| metrics.serviceMonitor.labels | object | `{}` | | +| metrics.serviceMonitor.metricRelabelings | list | `[]` | | +| metrics.serviceMonitor.namespace | string | `""` | | +| metrics.serviceMonitor.path | string | `"/metrics"` | | +| metrics.serviceMonitor.relabelings | list | `[]` | | +| metrics.serviceMonitor.scrapeTimeout | string | `""` | | +| migration.enabled | bool | `true` | | +| migration.postgresql.password | string | `""` | | +| migration.postgresql.url | string | `""` | | +| migration.postgresql.user | string | `""` | | +| nameOverride | string | `""` | | +| nodeEnv | string | `"production"` | | +| nodeSelector | object | `{}` | | +| persistence.accessModes[0] | string | `"ReadWriteOnce"` | | +| persistence.annotations | object | `{}` | | +| persistence.enabled | bool | `false` | | +| persistence.existingClaim | string | `""` | | +| persistence.mountPath | string | `"/data/pglite"` | | +| persistence.size | string | `"8Gi"` | | +| persistence.storageClass | string | `""` | | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| readinessProbe.httpGet.path | string | `"/readyz"` | | +| readinessProbe.httpGet.port | string | `"admin"` | | +| readinessProbe.initialDelaySeconds | int | `5` | | +| readinessProbe.periodSeconds | int | `10` | | +| replicaCount | int | `1` | | +| resources | object | `{}` | | +| securityContext | object | `{}` | | +| service.nodePorts.admin | string | `""` | | +| service.nodePorts.http | string | `""` | | +| service.ports.admin | int | `8091` | | +| service.ports.http | int | `80` | | +| service.targetPort.admin | string | `"admin"` | | +| service.targetPort.http | string | `"http"` | | +| service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.name | string | `""` | | +| tolerations | list | `[]` | | +| updateStrategy | object | `{}` | | +| volumeMounts | list | `[]` | | +| volumes | list | `[]` | | + diff --git a/charts/xapi-lrs/README.md.gotmpl b/charts/xapi-lrs/README.md.gotmpl new file mode 100644 index 0000000..a296de6 --- /dev/null +++ b/charts/xapi-lrs/README.md.gotmpl @@ -0,0 +1,15 @@ +{{ template "chart.header" . }} + +### version: {{ template "chart.version" . }} + +{{ template "chart.appVersionBadge" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/xapi-lrs/templates/NOTES.txt b/charts/xapi-lrs/templates/NOTES.txt new file mode 100644 index 0000000..6aa06fa --- /dev/null +++ b/charts/xapi-lrs/templates/NOTES.txt @@ -0,0 +1,42 @@ +1. Get the xAPI endpoint: +{{- if .Values.ingress.enabled }} + http{{ if .Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.hostname }}{{ .Values.ingress.path }} +{{- else if and .Values.gateway.enabled .Values.gateway.hostname }} + http{{ if .Values.gateway.listenerSet.enabled }}s{{ end }}://{{ .Values.gateway.hostname }}{{ .Values.gateway.httpRoute.path }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[?(@.name==\"http\")].nodePort}" services {{ include "xapi-lrs.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "http://$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "xapi-lrs.fullname" . }} -o jsonpath="{.status.loadBalancer.ingress[0].ip}") + echo "http://$SERVICE_IP:{{ .Values.service.ports.http }}" +{{- else }} + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "xapi-lrs.fullname" . }} 8081:{{ .Values.service.ports.http }} + # http://127.0.0.1:8081 +{{- end }} + + The admin UI is served under /admin on that same endpoint. + +2. The admin port serves unauthenticated /healthz, /readyz, and /metrics, and is + not routed externally. Reach it with a port-forward: + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "xapi-lrs.fullname" . }} 8091:{{ .Values.service.ports.admin }} + # http://127.0.0.1:8091/metrics + +{{- if eq .Values.database.driver "pglite" }} + +Running in PGlite mode (embedded, single-connection); not recommended for production. +{{- if not .Values.persistence.enabled }} +Data is in an emptyDir and will not survive a pod restart; set persistence.enabled=true +to keep it on a PVC. +{{- end }} +{{- end }} + +{{- if and (not .Values.auth.sessionSecret) (not .Values.auth.existingSecret) }} + +The admin session secret was generated automatically. It stays stable across +`helm upgrade`, but not under GitOps tools that render with `helm template` +(Argo CD, Flux), where it is regenerated on every sync. For those, set +auth.sessionSecret or auth.existingSecret. +{{- end }} diff --git a/charts/xapi-lrs/templates/_helpers.tpl b/charts/xapi-lrs/templates/_helpers.tpl new file mode 100644 index 0000000..a718621 --- /dev/null +++ b/charts/xapi-lrs/templates/_helpers.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "xapi-lrs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "xapi-lrs.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "xapi-lrs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "xapi-lrs.labels" -}} +helm.sh/chart: {{ include "xapi-lrs.chart" . }} +{{ include "xapi-lrs.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/component: lrs +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "xapi-lrs.selectorLabels" -}} +app.kubernetes.io/name: {{ include "xapi-lrs.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "xapi-lrs.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "xapi-lrs.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Return the proper xapi-lrs image name +*/}} +{{- define "xapi-lrs.image" -}} +{{- $registry := .Values.image.registry -}} +{{- $repository := .Values.image.repository -}} +{{- $ref := ternary (printf "@%s" .Values.image.digest) (printf ":%s" .Values.image.tag) (not (empty .Values.image.digest)) -}} +{{- if $registry -}} +{{- printf "%s/%s%s" $registry $repository $ref -}} +{{- else -}} +{{- printf "%s%s" $repository $ref -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the Secret holding the sensitive values +*/}} +{{- define "xapi-lrs.secretName" -}} +{{- default (include "xapi-lrs.fullname" .) .Values.auth.existingSecret -}} +{{- end -}} + +{{/* +Return auth.sessionSecret if set, else the value already in the chart Secret +(so upgrades don't rotate it), else a new random value. +*/}} +{{- define "xapi-lrs.sessionSecret" -}} +{{- if .Values.auth.sessionSecret -}} +{{- .Values.auth.sessionSecret -}} +{{- else -}} +{{- $existing := lookup "v1" "Secret" .Release.Namespace (include "xapi-lrs.fullname" .) -}} +{{- if and $existing $existing.data (index $existing.data "session-secret") -}} +{{- index $existing.data "session-secret" | b64dec -}} +{{- else -}} +{{- randAlphaNum 64 -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/xapi-lrs/templates/deployment.yaml b/charts/xapi-lrs/templates/deployment.yaml new file mode 100644 index 0000000..1f85b31 --- /dev/null +++ b/charts/xapi-lrs/templates/deployment.yaml @@ -0,0 +1,226 @@ +{{- if and (eq .Values.database.driver "pglite") (gt (int .Values.replicaCount) 1) }} +{{- fail "database.driver=pglite requires replicaCount=1" }} +{{- end }} +{{- if and (eq .Values.nodeEnv "production") .Values.cors.enabled (or (not .Values.cors.origin) (eq .Values.cors.origin "*")) }} +{{- fail "cors.origin must be set (and not \"*\") when cors.enabled=true and nodeEnv=production" }} +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + {{- if .Values.updateStrategy }} + strategy: + {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- else if and (eq .Values.database.driver "pglite") .Values.persistence.enabled }} + strategy: + type: Recreate + {{- end }} + selector: + matchLabels: + {{- include "xapi-lrs.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "xapi-lrs.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "xapi-lrs.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} + enableServiceLinks: {{ .Values.enableServiceLinks }} + {{- with .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if and .Values.migration.enabled (eq .Values.database.driver "pg") }} + initContainers: + - name: migrate + image: {{ include "xapi-lrs.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + command: ["node", "dist/migrate.js"] + env: + - name: LOG_LEVEL + value: {{ .Values.logLevel | quote }} + {{- $migUrl := .Values.migration.postgresql.url | default .Values.database.postgresql.url }} + {{- if $migUrl }} + - name: DATABASE_URL + value: {{ $migUrl | quote }} + {{- else }} + - name: PGHOST + value: {{ .Values.database.postgresql.host | quote }} + - name: PGPORT + value: {{ .Values.database.postgresql.port | quote }} + - name: PGDATABASE + value: {{ .Values.database.postgresql.database | quote }} + - name: PGUSER + value: {{ .Values.migration.postgresql.user | default .Values.database.postgresql.user | quote }} + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: {{ include "xapi-lrs.secretName" . }} + {{- if or .Values.migration.postgresql.user .Values.migration.postgresql.password }} + key: {{ .Values.auth.existingSecretKeys.migrationPostgresqlPassword }} + {{- else }} + key: {{ .Values.auth.existingSecretKeys.postgresqlPassword }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: {{ include "xapi-lrs.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + - name: XAPI_LRS_PORT + value: {{ .Values.containerPorts.http | quote }} + - name: XAPI_LRS_ADMIN_PORT + value: {{ .Values.containerPorts.admin | quote }} + {{- if .Values.nodeEnv }} + - name: NODE_ENV + value: {{ .Values.nodeEnv | quote }} + {{- end }} + - name: LOG_LEVEL + value: {{ .Values.logLevel | quote }} + - name: CORS_ENABLED + value: {{ .Values.cors.enabled | quote }} + {{- if .Values.cors.origin }} + - name: CORS_ORIGIN + value: {{ .Values.cors.origin | quote }} + {{- end }} + - name: XAPI_LRS_ADMIN_USER + value: {{ .Values.auth.adminUser | quote }} + - name: XAPI_LRS_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "xapi-lrs.secretName" . }} + key: {{ .Values.auth.existingSecretKeys.adminPassword }} + - name: ADMIN_SESSION_SECRET + valueFrom: + secretKeyRef: + name: {{ include "xapi-lrs.secretName" . }} + key: {{ .Values.auth.existingSecretKeys.sessionSecret }} + {{- if .Values.auth.apiKey }} + - name: XAPI_LRS_API_KEY_DEFAULT + value: {{ .Values.auth.apiKey | quote }} + - name: XAPI_LRS_API_SECRET_DEFAULT + valueFrom: + secretKeyRef: + name: {{ include "xapi-lrs.secretName" . }} + key: {{ .Values.auth.existingSecretKeys.apiSecret }} + {{- end }} + {{- if eq .Values.database.driver "pglite" }} + - name: DATABASE_DRIVER + value: pglite + {{- if .Values.persistence.enabled }} + - name: PGLITE_DATA_DIR + value: {{ .Values.persistence.mountPath | quote }} + {{- end }} + {{- else }} + {{- if .Values.database.postgresql.url }} + - name: DATABASE_URL + value: {{ .Values.database.postgresql.url | quote }} + {{- else }} + - name: PGHOST + value: {{ .Values.database.postgresql.host | quote }} + - name: PGPORT + value: {{ .Values.database.postgresql.port | quote }} + - name: PGDATABASE + value: {{ .Values.database.postgresql.database | quote }} + - name: PGUSER + value: {{ .Values.database.postgresql.user | quote }} + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: {{ include "xapi-lrs.secretName" . }} + key: {{ .Values.auth.existingSecretKeys.postgresqlPassword }} + {{- end }} + {{- end }} + {{- with .Values.extraEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ .Values.extraEnvVarsCM }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ .Values.extraEnvVarsSecret }} + {{- end }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.containerPorts.http }} + - name: admin + containerPort: {{ .Values.containerPorts.admin }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- $pgliteVol := and (eq .Values.database.driver "pglite") .Values.persistence.enabled }} + {{- if or $pgliteVol .Values.volumeMounts }} + volumeMounts: + {{- if $pgliteVol }} + - name: pglite-data + mountPath: {{ .Values.persistence.mountPath }} + {{- end }} + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if or $pgliteVol .Values.volumes }} + volumes: + {{- if $pgliteVol }} + - name: pglite-data + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "xapi-lrs.fullname" .) }} + {{- end }} + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/xapi-lrs/templates/httproute.yaml b/charts/xapi-lrs/templates/httproute.yaml new file mode 100644 index 0000000..cf77840 --- /dev/null +++ b/charts/xapi-lrs/templates/httproute.yaml @@ -0,0 +1,61 @@ +{{- if .Values.gateway.enabled }} +{{- if and .Values.gateway.listenerSet.enabled (or .Values.gateway.httpRoute.gatewayName .Values.gateway.httpRoute.gatewayNamespace .Values.gateway.httpRoute.sectionName .Values.gateway.httpRoute.port) }} +{{- fail "gateway.httpRoute.gatewayName/gatewayNamespace/sectionName/port are ignored when gateway.listenerSet.enabled is true — remove them or disable listenerSet" }} +{{- end }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- if or .Values.gateway.httpRoute.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.gateway.httpRoute.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + parentRefs: + {{- if .Values.gateway.listenerSet.enabled }} + - group: gateway.networking.k8s.io + kind: ListenerSet + name: {{ include "xapi-lrs.fullname" . }} + {{- else }} + - group: gateway.networking.k8s.io + kind: Gateway + name: {{ .Values.gateway.httpRoute.gatewayName | required "gateway.httpRoute.gatewayName is required when gateway.enabled is true and gateway.listenerSet.enabled is false" }} + {{- with .Values.gateway.httpRoute.gatewayNamespace }} + namespace: {{ . }} + {{- end }} + {{- with .Values.gateway.httpRoute.sectionName }} + sectionName: {{ . }} + {{- end }} + {{- with .Values.gateway.httpRoute.port }} + port: {{ . }} + {{- end }} + {{- end }} + {{- if or .Values.gateway.hostname .Values.gateway.httpRoute.extraHostnames }} + hostnames: + {{- with .Values.gateway.hostname }} + - {{ . | quote }} + {{- end }} + {{- range .Values.gateway.httpRoute.extraHostnames }} + - {{ . | quote }} + {{- end }} + {{- end }} + rules: + {{- if .Values.gateway.httpRoute.rules }} + {{- toYaml .Values.gateway.httpRoute.rules | nindent 4 }} + {{- else }} + - matches: + - path: + type: {{ .Values.gateway.httpRoute.pathType }} + value: {{ .Values.gateway.httpRoute.path }} + backendRefs: + - name: {{ include "xapi-lrs.fullname" . }} + port: {{ .Values.service.ports.http }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/ingress.yaml b/charts/xapi-lrs/templates/ingress.yaml new file mode 100644 index 0000000..800a9a9 --- /dev/null +++ b/charts/xapi-lrs/templates/ingress.yaml @@ -0,0 +1,60 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- if or .Values.ingress.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + {{- with .Values.ingress.ingressClassName }} + ingressClassName: {{ . | quote }} + {{- end }} + rules: + {{- if .Values.ingress.hostname }} + - host: {{ .Values.ingress.hostname | quote }} + http: + paths: + {{- with .Values.ingress.extraPaths }} + {{- toYaml . | nindent 10 }} + {{- end }} + - path: {{ .Values.ingress.path }} + pathType: {{ .Values.ingress.pathType }} + backend: + service: + name: {{ include "xapi-lrs.fullname" . }} + port: + name: http + {{- end }} + {{- range .Values.ingress.extraHosts }} + - host: {{ .name | quote }} + http: + paths: + - path: {{ default "/" .path }} + pathType: {{ default "ImplementationSpecific" .pathType }} + backend: + service: + name: {{ include "xapi-lrs.fullname" $ }} + port: + name: http + {{- end }} + {{- if or (and .Values.ingress.tls .Values.ingress.hostname) .Values.ingress.extraTls }} + tls: + {{- if and .Values.ingress.tls .Values.ingress.hostname }} + - hosts: + - {{ .Values.ingress.hostname | quote }} + secretName: {{ printf "%s-tls" .Values.ingress.hostname }} + {{- end }} + {{- with .Values.ingress.extraTls }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/listenerset.yaml b/charts/xapi-lrs/templates/listenerset.yaml new file mode 100644 index 0000000..001aa23 --- /dev/null +++ b/charts/xapi-lrs/templates/listenerset.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.gateway.enabled .Values.gateway.listenerSet.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: ListenerSet +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- if or .Values.gateway.listenerSet.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.gateway.listenerSet.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: {{ .Values.gateway.listenerSet.gatewayName | required "gateway.listenerSet.gatewayName is required when gateway.listenerSet.enabled is true" }} + {{- with .Values.gateway.listenerSet.gatewayNamespace }} + namespace: {{ . }} + {{- end }} + listeners: + {{- if .Values.gateway.listenerSet.listeners }} + {{- toYaml .Values.gateway.listenerSet.listeners | nindent 4 }} + {{- else if .Values.gateway.listenerSet.https.enabled }} + - name: https + protocol: HTTPS + port: 443 + hostname: {{ .Values.gateway.hostname | required "gateway.hostname is required when gateway.listenerSet.enabled is true" | quote }} + tls: + mode: Terminate + certificateRefs: + - name: {{ default (printf "%s-tls" .Values.gateway.hostname) .Values.gateway.listenerSet.https.secretName | quote }} + allowedRoutes: + namespaces: + from: Same + {{- else }} + {{- fail "gateway.listenerSet requires either gateway.listenerSet.https.enabled or a non-empty gateway.listenerSet.listeners" }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/pvc.yaml b/charts/xapi-lrs/templates/pvc.yaml new file mode 100644 index 0000000..ca60351 --- /dev/null +++ b/charts/xapi-lrs/templates/pvc.yaml @@ -0,0 +1,25 @@ +{{- if and (eq .Values.database.driver "pglite") .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- toYaml .Values.persistence.accessModes | nindent 4 }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/secret.yaml b/charts/xapi-lrs/templates/secret.yaml new file mode 100644 index 0000000..70228c0 --- /dev/null +++ b/charts/xapi-lrs/templates/secret.yaml @@ -0,0 +1,21 @@ +{{- if not .Values.auth.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: + admin-password: {{ .Values.auth.adminPassword | b64enc | quote }} + session-secret: {{ include "xapi-lrs.sessionSecret" . | b64enc | quote }} + postgresql-password: {{ .Values.database.postgresql.password | b64enc | quote }} + migration-postgresql-password: {{ .Values.migration.postgresql.password | default .Values.database.postgresql.password | b64enc | quote }} + {{- if .Values.auth.apiSecret }} + api-secret: {{ .Values.auth.apiSecret | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/service.yaml b/charts/xapi-lrs/templates/service.yaml new file mode 100644 index 0000000..cd51fe4 --- /dev/null +++ b/charts/xapi-lrs/templates/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "xapi-lrs.fullname" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - name: http + port: {{ .Values.service.ports.http }} + targetPort: {{ .Values.service.targetPort.http }} + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.http }} + nodePort: {{ .Values.service.nodePorts.http }} + {{- end }} + - name: admin + port: {{ .Values.service.ports.admin }} + targetPort: {{ .Values.service.targetPort.admin }} + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.admin }} + nodePort: {{ .Values.service.nodePorts.admin }} + {{- end }} + selector: + {{- include "xapi-lrs.selectorLabels" . | nindent 4 }} diff --git a/charts/xapi-lrs/templates/serviceaccount.yaml b/charts/xapi-lrs/templates/serviceaccount.yaml new file mode 100644 index 0000000..6d85602 --- /dev/null +++ b/charts/xapi-lrs/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "xapi-lrs.serviceAccountName" . }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/xapi-lrs/templates/servicemonitor.yaml b/charts/xapi-lrs/templates/servicemonitor.yaml new file mode 100644 index 0000000..ca4a667 --- /dev/null +++ b/charts/xapi-lrs/templates/servicemonitor.yaml @@ -0,0 +1,35 @@ +{{- if .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "xapi-lrs.fullname" . }} + namespace: {{ default .Release.Namespace .Values.metrics.serviceMonitor.namespace }} + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + {{- with .Values.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "xapi-lrs.selectorLabels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + endpoints: + - port: admin + path: {{ .Values.metrics.serviceMonitor.path }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- with .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/xapi-lrs/templates/tests/test-connection.yaml b/charts/xapi-lrs/templates/tests/test-connection.yaml new file mode 100644 index 0000000..991f60b --- /dev/null +++ b/charts/xapi-lrs/templates/tests/test-connection.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "xapi-lrs.fullname" . }}-test-connection" + labels: + {{- include "xapi-lrs.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: readyz + image: busybox + command: ['wget'] + args: + - '--spider' + - '-S' + - '{{ include "xapi-lrs.fullname" . }}:{{ .Values.service.ports.admin }}/readyz' + restartPolicy: Never diff --git a/charts/xapi-lrs/values.yaml b/charts/xapi-lrs/values.yaml new file mode 100644 index 0000000..6912677 --- /dev/null +++ b/charts/xapi-lrs/values.yaml @@ -0,0 +1,426 @@ +# Default values for xapi-lrs. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +## @param replicaCount Number of xapi-lrs replicas to deploy. Must be 1 when database.driver=pglite. +## +replicaCount: 1 + +## @param updateStrategy Deployment update strategy. Defaults to Recreate in pglite mode with persistence +## (a ReadWriteOnce volume cannot attach to a new pod while the old one holds it), RollingUpdate otherwise. +## e.g: +## updateStrategy: +## type: RollingUpdate +## rollingUpdate: +## maxUnavailable: 0 +## +updateStrategy: {} + +image: + ## @param image.registry Container image registry + ## + registry: ghcr.io + ## @param image.repository Container image repository + ## + repository: pelotech/xapi-lrs + ## @param image.tag Container image tag + ## + tag: 0.7.1 + ## @param image.digest Image digest in the form sha256:aaaa... . When set, takes precedence over image.tag + ## + digest: "sha256:5edc504b19375c5b19e7e3289308d227fb6b219f6226488d1360ff0c8e5d87ac" + ## @param image.pullPolicy Image pull policy + ## + pullPolicy: IfNotPresent + ## @param image.pullSecrets Image pull secrets + ## e.g: + ## pullSecrets: + ## - name: ghcr-credentials + ## + pullSecrets: [] + +## @param nameOverride String to partially override the fullname template (release name is kept) +## +nameOverride: "" +## @param fullnameOverride String to fully override the fullname template +## +fullnameOverride: "" + +serviceAccount: + ## @param serviceAccount.create Whether to create a ServiceAccount + ## + create: true + ## @param serviceAccount.name Name of the ServiceAccount to use. If not set and create is true, a name is generated + ## + name: "" + ## @param serviceAccount.annotations Annotations to add to the ServiceAccount + ## + annotations: {} + +## @param automountServiceAccountToken Mount the ServiceAccount token in the pod. The app needs no Kubernetes API access. +## +automountServiceAccountToken: false + +## @param enableServiceLinks Inject Kubernetes service-link env vars into the pod. Kept false because the Service +## name uppercases to XAPI_LRS_, so a link var (XAPI_LRS_PORT=tcp://...) would collide with the app's config and crash it. +## +enableServiceLinks: false + +containerPorts: + ## @param containerPorts.http xAPI HTTP API port (XAPI_LRS_PORT) + ## + http: 8081 + ## @param containerPorts.admin Health and metrics port (XAPI_LRS_ADMIN_PORT). Serves unauthenticated + ## /healthz, /readyz, /metrics. The admin UI is on the http port at /admin, not here. + ## + admin: 8091 + +## @param nodeEnv Sets NODE_ENV. In "production" the app requires a session secret and a non-wildcard +## CORS origin when CORS is enabled. +## +nodeEnv: "production" + +## @param logLevel Application log level (silent/fatal/error/warn/info/debug/trace) -> LOG_LEVEL +## +logLevel: info + +cors: + ## @param cors.enabled Enable CORS handling in the app (CORS_ENABLED). When false, CORS is left to the proxy. + ## + enabled: false + ## @param cors.origin Allowed CORS origin (CORS_ORIGIN). Required (non-"*") when cors.enabled=true and nodeEnv=production. + ## + origin: "" + +database: + ## @param database.driver Database driver: "pg" (external PostgreSQL) or "pglite" (embedded, single-connection) + ## + driver: pg + postgresql: + ## @param database.postgresql.host PostgreSQL host (PGHOST). Ignored when database.postgresql.url is set. + ## + host: postgres + ## @param database.postgresql.port PostgreSQL port (PGPORT) + ## + port: 5432 + ## @param database.postgresql.database PostgreSQL database name (PGDATABASE) + ## + database: xapi_lrs + ## @param database.postgresql.user Runtime (DML) PostgreSQL user (PGUSER) + ## + user: xapi_lrs + ## @param database.postgresql.password Runtime (DML) PostgreSQL password (PGPASSWORD). Stored in the chart Secret. + ## + password: "" + ## @param database.postgresql.url Full connection string (DATABASE_URL). Overrides the PG* settings above. + ## Rendered as a plain env value, so any embedded password is visible in the pod spec. + ## + url: "" + +migration: + ## @param migration.enabled Run schema migrations in an init container before the app starts. + ## Skipped when database.driver=pglite. + ## + enabled: true + ## Credentials for the migration init container, for running migrations as a role + ## with DDL permissions. Each falls back to its database.postgresql counterpart when empty. + postgresql: + ## @param migration.postgresql.user PostgreSQL user for migrations + ## + user: "" + ## @param migration.postgresql.password PostgreSQL password for migrations + ## + password: "" + ## @param migration.postgresql.url Full connection string for migrations (DATABASE_URL on the init container). + ## Like database.postgresql.url, any embedded password is visible in the pod spec. + ## + url: "" + +auth: + ## @param auth.adminUser Bootstrap admin username (XAPI_LRS_ADMIN_USER) + ## + adminUser: admin + ## @param auth.adminPassword Bootstrap admin password (XAPI_LRS_ADMIN_PASSWORD). Stored in the chart Secret. + ## + adminPassword: "" + ## @param auth.sessionSecret Admin session secret (ADMIN_SESSION_SECRET). + ## If empty, a random value is generated on install and reused on upgrades via a cluster lookup. + ## That lookup only works with `helm install`/`helm upgrade`; under GitOps (Argo/Flux render with + ## `helm template`) the value is regenerated on every sync, so set this explicitly or use auth.existingSecret. + ## + sessionSecret: "" + ## @param auth.apiKey Bootstrap xAPI credential key (XAPI_LRS_API_KEY_DEFAULT). Leave empty to not bootstrap a credential. + ## + apiKey: "" + ## @param auth.apiSecret Bootstrap xAPI credential secret (XAPI_LRS_API_SECRET_DEFAULT). Stored in the chart Secret. + ## + apiSecret: "" + ## @param auth.existingSecret Name of an existing Secret holding the sensitive values. When set, the chart Secret is not created. + ## The Secret must contain the keys below for the features you use: admin-password and session-secret always; + ## postgresql-password in pg mode; migration-postgresql-password only if migration.postgresql.user/password is set; + ## api-secret only if auth.apiKey is set. + ## + existingSecret: "" + ## Keys to read from auth.existingSecret. + existingSecretKeys: + ## @param auth.existingSecretKeys.adminPassword Key for XAPI_LRS_ADMIN_PASSWORD + adminPassword: admin-password + ## @param auth.existingSecretKeys.sessionSecret Key for ADMIN_SESSION_SECRET + sessionSecret: session-secret + ## @param auth.existingSecretKeys.apiSecret Key for XAPI_LRS_API_SECRET_DEFAULT + apiSecret: api-secret + ## @param auth.existingSecretKeys.postgresqlPassword Key for the runtime PGPASSWORD + postgresqlPassword: postgresql-password + ## @param auth.existingSecretKeys.migrationPostgresqlPassword Key for the migration (DDL) PGPASSWORD + migrationPostgresqlPassword: migration-postgresql-password + +## @param extraEnvVars Extra environment variables to set on the container(s) +## E.g: +## extraEnvVars: +## - name: JWT_ISSUER +## value: https://issuer.example.com +## +extraEnvVars: [] +## @param extraEnvVarsCM Name of a ConfigMap with extra environment variables +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Name of a Secret with extra environment variables +## +extraEnvVarsSecret: "" + +## @param commonAnnotations Annotations to add to the Deployment +## +commonAnnotations: {} +## @param podAnnotations Annotations to add to the pods +## +podAnnotations: {} +## @param podLabels Extra labels to add to the pods +## +podLabels: {} +## @param podSecurityContext Pod-level security context +## +podSecurityContext: {} + # fsGroup: 2000 +## @param securityContext Container-level security context +## +securityContext: {} + # runAsNonRoot: true + # runAsUser: 1000 + # readOnlyRootFilesystem: true + +service: + ## @param service.type Kubernetes Service type + ## + type: ClusterIP + ports: + ## @param service.ports.http xAPI HTTP service port + ## + http: 80 + ## @param service.ports.admin Admin service port + ## + admin: 8091 + targetPort: + ## @param service.targetPort.http Target container port name for http + ## + http: http + ## @param service.targetPort.admin Target container port name for admin + ## + admin: admin + nodePorts: + ## @param service.nodePorts.http NodePort for http (only when type is NodePort/LoadBalancer) + ## + http: "" + ## @param service.nodePorts.admin NodePort for admin (only when type is NodePort/LoadBalancer) + ## + admin: "" + +## Ingress and Gateway route to the http (xAPI) port only; the admin port stays on the Service. +ingress: + ## @param ingress.enabled Enable Ingress record generation (targets the http/xAPI port) + ## + enabled: false + ## @param ingress.ingressClassName IngressClass name + ## + ingressClassName: "" + ## @param ingress.pathType Ingress path type + ## + pathType: ImplementationSpecific + ## @param ingress.hostname Default host for the ingress record + ## + hostname: xapi-lrs.local + ## @param ingress.path Default path for the ingress record + ## + path: / + ## @param ingress.annotations Additional annotations for the Ingress resource (e.g. cert-manager) + ## + annotations: {} + ## @param ingress.tls Enable TLS; expects a secret named "-tls" + ## + tls: false + ## @param ingress.extraHosts Additional hosts: list of {name, path?, pathType?} + ## + extraHosts: [] + ## @param ingress.extraPaths Additional arbitrary paths under the main host + ## + extraPaths: [] + ## @param ingress.extraTls Additional TLS configuration blocks + ## + extraTls: [] + +gateway: + ## @param gateway.enabled Enable Gateway API resource generation (HTTPRoute and optional ListenerSet). Targets the http/xAPI port. + ## + enabled: false + ## @param gateway.hostname Hostname for the HTTPRoute and ListenerSet listeners + ## + hostname: "" + httpRoute: + ## @param gateway.httpRoute.gatewayName Name of the parent Gateway. Required when listenerSet.enabled is false. + ## + gatewayName: "" + ## @param gateway.httpRoute.gatewayNamespace Namespace of the parent Gateway + ## + gatewayNamespace: "" + ## @param gateway.httpRoute.sectionName Target a specific listener on the parent Gateway + ## + sectionName: "" + ## @param gateway.httpRoute.port Target a specific port on the parent Gateway + ## + port: "" + ## @param gateway.httpRoute.annotations Annotations for the HTTPRoute + ## + annotations: {} + ## @param gateway.httpRoute.extraHostnames Additional hostnames for the HTTPRoute + ## + extraHostnames: [] + ## @param gateway.httpRoute.path Default path match value + ## + path: / + ## @param gateway.httpRoute.pathType Default path match type + ## + pathType: PathPrefix + ## @param gateway.httpRoute.rules Full rules override. If set, replaces the auto-generated default rule. + ## + rules: [] + listenerSet: + ## @param gateway.listenerSet.enabled Enable ListenerSet generation. When true, the HTTPRoute parents to the ListenerSet. + ## + enabled: false + ## @param gateway.listenerSet.gatewayName Name of the parent Gateway. Required when listenerSet.enabled is true. + ## + gatewayName: "" + ## @param gateway.listenerSet.gatewayNamespace Namespace of the parent Gateway + ## + gatewayNamespace: "" + https: + ## @param gateway.listenerSet.https.enabled Auto-generate an HTTPS listener + ## + enabled: true + ## @param gateway.listenerSet.https.secretName TLS secret name. Defaults to "-tls" if empty. + ## + secretName: "" + ## @param gateway.listenerSet.annotations Annotations for the ListenerSet + ## + annotations: {} + ## @param gateway.listenerSet.listeners Full listeners override. If empty, auto-generates from gateway.listenerSet.https. + ## + listeners: [] + +metrics: + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create a Prometheus Operator ServiceMonitor scraping the admin port + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace for the ServiceMonitor (defaults to the release namespace) + ## + namespace: "" + ## @param metrics.serviceMonitor.path Metrics path on the admin port + ## + path: /metrics + ## @param metrics.serviceMonitor.interval Scrape interval + ## + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout Scrape timeout + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.labels Extra labels for the ServiceMonitor (for Prometheus selector matching) + ## + labels: {} + ## @param metrics.serviceMonitor.honorLabels Honor labels from the scraped metrics + ## + honorLabels: false + ## @param metrics.serviceMonitor.relabelings Relabeling rules applied to samples before scraping + ## + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings Relabeling rules applied to samples before ingestion + ## + metricRelabelings: [] + +## @param resources Resource requests/limits for the container +## +resources: {} + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + ## @param livenessProbe Liveness probe. Defaults to GET /healthz on the admin port. + ## + httpGet: + path: /healthz + port: admin + initialDelaySeconds: 10 + periodSeconds: 10 +readinessProbe: + ## @param readinessProbe Readiness probe. Defaults to GET /readyz on the admin port. + ## + httpGet: + path: /readyz + port: admin + initialDelaySeconds: 5 + periodSeconds: 10 + +## @param volumes Additional volumes on the Deployment +## +volumes: [] +## @param volumeMounts Additional volumeMounts on the container +## +volumeMounts: [] + +## @param nodeSelector Node labels for pod assignment +## +nodeSelector: {} +## @param tolerations Tolerations for pod assignment +## +tolerations: [] +## @param affinity Affinity for pod assignment +## +affinity: {} + +## Storage for the embedded database in PGlite mode. Ignored when database.driver=pg. +persistence: + ## @param persistence.enabled Persist the PGlite database on a PVC. If false, data is lost on pod restart. + ## + enabled: false + ## @param persistence.existingClaim Name of an existing PVC to use instead of creating one + ## + existingClaim: "" + ## @param persistence.mountPath Path where the PGlite data directory is mounted + ## + mountPath: /data/pglite + ## @param persistence.storageClass PVC storage class ("-" disables dynamic provisioning; "" uses the default) + ## + storageClass: "" + ## @param persistence.accessModes PVC access modes + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC storage request + ## + size: 8Gi + ## @param persistence.annotations Annotations for the PVC + ## + annotations: {} diff --git a/release-please-config.json b/release-please-config.json index cb66456..778b60f 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -41,6 +41,9 @@ }, "charts/postgrest": { "extra-files": ["README.md"] + }, + "charts/xapi-lrs": { + "extra-files": ["README.md"] } }, "changelog-sections": [