Helm update

This commit is contained in:
Josh Belke 2026-07-08 07:36:35 -04:00
commit 00ae555710
14 changed files with 353 additions and 935 deletions

View file

@ -1,9 +1,41 @@
# Local development runtime for the R2D2 — Task Force X FMV console.
#
# Profiles:
# dev — Uptime Kuma only (the monitoring engine).
# docker compose --profile dev up
# full — Kuma + the R2D2 Ops console (operator SPA + media proxy + recorder).
# docker compose --profile full up
#
# The Ops console logs into Kuma with ADMIN_USER / ADMIN_PASS, so seed Kuma with
# the same credentials first (see .settings/seed). Feeds on the NetBird mesh
# read as pending locally — that's expected without the mesh sidecar.
services:
uptime-kuma:
image: louislam/uptime-kuma:2
profiles: ["dev", "full"]
restart: unless-stopped
volumes:
- ./data:/app/data
ports:
# <Host Port>:<Container Port>
- "3001:3001"
ops-console:
profiles: ["full"]
build:
context: .
dockerfile: docker/ops-console.dockerfile
restart: unless-stopped
depends_on:
- uptime-kuma
environment:
KUMA_URL: "http://uptime-kuma:3001"
OPS_BIND: "0.0.0.0"
ADMIN_USER: "${ADMIN_USER:-NATO}"
ADMIN_PASS: "${ADMIN_PASS:-NATO1949}"
# OPS_SECRET: set this to gate the mutating endpoints before exposing the
# console beyond localhost.
volumes:
- ./data/recordings:/recordings
ports:
- "4013:4013"

View file

@ -0,0 +1,37 @@
# R2D2 Ops console — operator SPA + Kuma proxy + snapshot/HLS + recorder.
# Layers on top of Uptime Kuma, which runs in its own container; this image
# only carries the .settings/ops server. See README "Architecture".
#
# Build from the repository ROOT (it needs both .settings/ops and the seed plan):
# docker build -f docker/ops-console.dockerfile -t r2d2-ops-console:latest .
FROM node:20-bookworm-slim
# ffmpeg/ffprobe: the recorder spawns ffmpeg for clip + snapshot capture and
# klv-probe.sh shells out to ffprobe.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Layout mirrors the repo: serve.mjs resolves ../seed/monitors.json relative to
# its own directory, so ops/ and seed/ must stay siblings.
WORKDIR /app/ops
# socket.io-client is the only third-party runtime dep (server-side Kuma login).
# serve.mjs require()s it from its own dir first, so install it here.
RUN npm init -y >/dev/null \
&& npm install --omit=dev socket.io-client@^4.8.1 \
&& npm cache clean --force
# App code: ops server, recorder, SPA, vendored hls.js, probe helpers.
COPY .settings/ops/ ./
# serve.mjs reads the committed seed plan for monitor metadata (../seed/...).
COPY .settings/seed/monitors.json /app/seed/monitors.json
# Recordings land here by default; mount a volume/PVC over it to persist them.
RUN mkdir -p /recordings
ENV OPS_PORT=4013 \
OPS_BIND=0.0.0.0 \
REC_ROOT=/recordings
EXPOSE 4013
CMD ["node", "serve.mjs"]

View file

@ -1,10 +1,11 @@
apiVersion: v2
name: r2d2-status
description: R2D2-Status — Gatus health dashboard for service monitoring
description: R2D2-Status — Uptime Kuma monitoring + R2D2 Ops console for Task Force X
type: application
version: 0.2.0
appVersion: "5"
version: 0.3.0
appVersion: "2.4.0"
keywords:
- status
- monitoring
- gatus
- uptime-kuma
- fmv

View file

@ -1,12 +1,18 @@
R2D2-Status ({{ .Chart.Name }}-{{ .Chart.Version }}) deployed.
Storage backend: {{ .Values.storage.type }}
Uptime Kuma {{ .Values.kuma.image.tag }} + R2D2 Ops console.
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
URL: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
Ops console: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- else }}
Port-forward to reach the dashboard:
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "r2d2-status.fullname" . }} 8080:{{ .Values.service.port }}
Then open http://localhost:8080
Port-forward to reach the consoles:
# Ops console (operator SPA + status pages)
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "r2d2-status.fullname" . }} {{ .Values.opsConsole.port }}:{{ .Values.service.port }}
# Kuma admin dashboard
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "r2d2-status.fullname" . }} {{ .Values.kuma.port }}:{{ .Values.service.kumaPort }}
Then open http://localhost:{{ .Values.opsConsole.port }} (ops) or http://localhost:{{ .Values.kuma.port }} (kuma).
{{- end }}
NOTE: Kuma starts empty. Seed it with the same admin credentials the Ops
console uses (auth.*), then the console can log in. See .settings/seed.

View file

@ -57,10 +57,18 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/* Name of the secret holding DATABASE_URL for postgres storage */}}
{{- define "r2d2-status.postgresSecretName" -}}
{{- if .Values.storage.postgres.existingSecret }}
{{- .Values.storage.postgres.existingSecret }}
{{- define "r2d2-status.authSecretName" -}}
{{- if .Values.auth.existingSecret }}
{{- .Values.auth.existingSecret }}
{{- else }}
{{- printf "%s-db" (include "r2d2-status.fullname" .) }}
{{- printf "%s-auth" (include "r2d2-status.fullname" .) }}
{{- end }}
{{- end }}
{{- define "r2d2-status.opsSecretName" -}}
{{- if .Values.opsConsole.secret.existingSecret }}
{{- .Values.opsConsole.secret.existingSecret }}
{{- else }}
{{- printf "%s-ops" (include "r2d2-status.fullname" .) }}
{{- end }}
{{- end }}

View file

@ -1,17 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "r2d2-status.fullname" . }}
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
data:
config.yaml: |
storage:
type: {{ .Values.storage.type }}
{{- if eq .Values.storage.type "sqlite" }}
path: /data/gatus.db
{{- else if eq .Values.storage.type "postgres" }}
path: ${DATABASE_URL}
{{- end }}
{{- .Values.config | nindent 4 }}

View file

@ -5,21 +5,19 @@ metadata:
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
spec:
{{- if and (gt (int .Values.replicaCount) 1) (ne .Values.storage.type "postgres") }}
{{- fail "replicaCount > 1 requires storage.type=postgres (memory/sqlite are per-pod)" }}
{{- if gt (int .Values.replicaCount) 1 }}
{{- fail "replicaCount > 1 is unsupported: Kuma stores state in a per-pod SQLite DB" }}
{{- end }}
replicas: {{ .Values.replicaCount }}
{{- if eq .Values.storage.type "sqlite" }}
# Kuma's SQLite PVC is ReadWriteOnce — never run two pods against it at once.
strategy:
type: Recreate
{{- end }}
selector:
matchLabels:
{{- include "r2d2-status.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
@ -37,28 +35,72 @@ spec:
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: gatus
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
# --- Uptime Kuma: the monitoring engine ---------------------------
- name: kuma
image: "{{ .Values.kuma.image.repository }}:{{ .Values.kuma.image.tag }}"
imagePullPolicy: {{ .Values.kuma.image.pullPolicy }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
ports:
- name: http
containerPort: 8080
- name: kuma
containerPort: {{ .Values.kuma.port }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: kuma
initialDelaySeconds: 30
periodSeconds: 20
readinessProbe:
httpGet:
path: /
port: kuma
initialDelaySeconds: 10
periodSeconds: 10
resources:
{{- toYaml .Values.kuma.resources | nindent 12 }}
volumeMounts:
- name: kuma-data
mountPath: /app/data
# --- R2D2 Ops console: SPA + media proxy + recorder ---------------
- name: ops-console
image: "{{ .Values.opsConsole.image.repository }}:{{ .Values.opsConsole.image.tag }}"
imagePullPolicy: {{ .Values.opsConsole.image.pullPolicy }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
ports:
- name: ops
containerPort: {{ .Values.opsConsole.port }}
protocol: TCP
env:
- name: GATUS_CONFIG_PATH
value: /config/config.yaml
- name: GATUS_LOG_LEVEL
value: {{ .Values.logLevel | quote }}
{{- if eq .Values.storage.type "postgres" }}
- name: DATABASE_URL
- name: KUMA_URL
value: "http://localhost:{{ .Values.kuma.port }}"
- name: OPS_PORT
value: {{ .Values.opsConsole.port | quote }}
- name: OPS_BIND
value: {{ .Values.opsConsole.bind | quote }}
- name: ADMIN_USER
valueFrom:
secretKeyRef:
name: {{ include "r2d2-status.postgresSecretName" . }}
key: DATABASE_URL
name: {{ include "r2d2-status.authSecretName" . }}
key: ADMIN_USER
- name: ADMIN_PASS
valueFrom:
secretKeyRef:
name: {{ include "r2d2-status.authSecretName" . }}
key: ADMIN_PASS
{{- if or .Values.opsConsole.secret.existingSecret .Values.opsConsole.secret.value }}
- name: OPS_SECRET
valueFrom:
secretKeyRef:
name: {{ include "r2d2-status.opsSecretName" . }}
key: OPS_SECRET
{{- end }}
{{- range $name, $value := .Values.env }}
{{- if .Values.opsConsole.recordings.enabled }}
- name: REC_ROOT
value: {{ .Values.opsConsole.recordings.mountPath | quote }}
{{- end }}
{{- range $name, $value := .Values.opsConsole.env }}
- name: {{ $name }}
value: {{ $value | quote }}
{{- end }}
@ -67,19 +109,16 @@ spec:
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- toYaml .Values.opsConsole.resources | nindent 12 }}
{{- if .Values.opsConsole.recordings.enabled }}
volumeMounts:
- name: config
mountPath: /config
readOnly: true
{{- if eq .Values.storage.type "sqlite" }}
- name: data
mountPath: /data
{{- end }}
- name: recordings
mountPath: {{ .Values.opsConsole.recordings.mountPath }}
{{- end }}
{{- if .Values.netbird.enabled }}
# VPN mesh sidecar — authenticates with a setup key (no PAT).
# Runs as root with NET_ADMIN (overrides pod securityContext), matching
# the holovids/nodered sidecars; userspace WireGuard, cluster DNS kept.
# VPN mesh sidecar — authenticates with a setup key (no PAT). Runs as
# root with NET_ADMIN (overrides pod securityContext), matching the
# holovids/nodered sidecars; userspace WireGuard, cluster DNS kept.
- name: netbird
image: {{ .Values.netbird.image }}
env:
@ -111,21 +150,26 @@ spec:
mountPath: /var/lib/netbird
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "r2d2-status.fullname" . }}
{{- if .Values.netbird.enabled }}
- name: netbird-state
emptyDir: {}
{{- end }}
{{- if eq .Values.storage.type "sqlite" }}
- name: data
{{- if .Values.storage.persistence.enabled }}
- name: kuma-data
{{- if .Values.kuma.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.storage.persistence.existingClaim | default (printf "%s-data" (include "r2d2-status.fullname" .)) }}
claimName: {{ .Values.kuma.persistence.existingClaim | default (printf "%s-kuma-data" (include "r2d2-status.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- if .Values.opsConsole.recordings.enabled }}
- name: recordings
{{- if .Values.opsConsole.recordings.existingClaim }}
persistentVolumeClaim:
claimName: {{ .Values.opsConsole.recordings.existingClaim }}
{{- else }}
persistentVolumeClaim:
claimName: {{ printf "%s-recordings" (include "r2d2-status.fullname" .) }}
{{- end }}
{{- end }}
{{- if .Values.netbird.enabled }}
- name: netbird-state
emptyDir: {}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:

View file

@ -35,7 +35,7 @@ spec:
service:
name: {{ include "r2d2-status.fullname" $ }}
port:
name: http
name: ops
{{- end }}
{{- end }}
{{- end }}

View file

@ -1,8 +1,8 @@
{{- if and (eq .Values.storage.type "sqlite") .Values.storage.persistence.enabled (not .Values.storage.persistence.existingClaim) }}
{{- if and .Values.kuma.persistence.enabled (not .Values.kuma.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "r2d2-status.fullname" . }}-data
name: {{ include "r2d2-status.fullname" . }}-kuma-data
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
spec:
@ -10,8 +10,26 @@ spec:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.storage.persistence.size }}
{{- with .Values.storage.persistence.storageClass }}
storage: {{ .Values.kuma.persistence.size }}
{{- with .Values.kuma.persistence.storageClass }}
storageClassName: {{ . }}
{{- end }}
{{- end }}
{{- if and .Values.opsConsole.recordings.enabled (not .Values.opsConsole.recordings.existingClaim) }}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "r2d2-status.fullname" . }}-recordings
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.opsConsole.recordings.size }}
{{- with .Values.opsConsole.recordings.storageClass }}
storageClassName: {{ . }}
{{- end }}
{{- end }}

View file

@ -1,14 +1,29 @@
{{- if and (eq .Values.storage.type "postgres") (not .Values.storage.postgres.existingSecret) }}
{{- if not .Values.storage.postgres.connectionString }}
{{- fail "storage.type=postgres requires storage.postgres.existingSecret or storage.postgres.connectionString" }}
{{- /* Admin credentials for the Ops console to log into Kuma. */ -}}
{{- if not .Values.auth.existingSecret }}
{{- if or (not .Values.auth.adminUser) (not .Values.auth.adminPass) }}
{{- fail "auth requires auth.existingSecret OR both auth.adminUser and auth.adminPass" }}
{{- end }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "r2d2-status.postgresSecretName" . }}
name: {{ include "r2d2-status.authSecretName" . }}
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
type: Opaque
stringData:
DATABASE_URL: {{ .Values.storage.postgres.connectionString | quote }}
ADMIN_USER: {{ .Values.auth.adminUser | quote }}
ADMIN_PASS: {{ .Values.auth.adminPass | quote }}
{{- end }}
{{- /* Ops console shared secret (x-ops-secret header on mutating requests). */ -}}
{{- if and .Values.opsConsole.secret.value (not .Values.opsConsole.secret.existingSecret) }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "r2d2-status.opsSecretName" . }}
labels:
{{- include "r2d2-status.labels" . | nindent 4 }}
type: Opaque
stringData:
OPS_SECRET: {{ .Values.opsConsole.secret.value | quote }}
{{- end }}

View file

@ -16,9 +16,9 @@ spec:
{{- end }}
ports:
- port: {{ .Values.service.loadBalancer.port }}
targetPort: http
targetPort: ops
protocol: TCP
name: http
name: ops
selector:
{{- include "r2d2-status.selectorLabels" . | nindent 4 }}
{{- end }}

View file

@ -8,8 +8,12 @@ spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
targetPort: ops
protocol: TCP
name: http
name: ops
- port: {{ .Values.service.kumaPort }}
targetPort: kuma
protocol: TCP
name: kuma
selector:
{{- include "r2d2-status.selectorLabels" . | nindent 4 }}

View file

@ -3,17 +3,34 @@
# -f ./helm/values.override.yml
# This file is .helmignore'd so it never ships inside the packaged chart.
image:
repository: git.office.ilab.zone/raid/r2d2-status
tag: "0.1.1"
# Ops console image, built from docker/ops-console.dockerfile and pushed to the
# office Gitea registry. Kuma pulls straight from Docker Hub (default values).
opsConsole:
image:
repository: git.office.ilab.zone/raid/r2d2-ops-console
tag: "0.3.0"
# Gate the mutating endpoints once the console is exposed. Prefer a Secret:
# kubectl -n r2d2-status create secret generic r2d2-ops --from-literal=OPS_SECRET=...
secret:
existingSecret: r2d2-ops
# Recorded clips/snapshots on Longhorn.
recordings:
enabled: true
size: 20Gi
# Same pull secret the other raid apps use; copied from the farsight namespace.
imagePullSecrets:
- name: gitea-registry-cred
# sqlite on Longhorn — single replica, self-contained (no external postgres).
storage:
type: sqlite
# Admin credentials the ops console logs into Kuma with — must match the seeded
# Kuma admin. Provide a Secret (keys ADMIN_USER / ADMIN_PASS), don't inline them:
# kubectl -n r2d2-status create secret generic r2d2-auth \
# --from-literal=ADMIN_USER=... --from-literal=ADMIN_PASS=...
auth:
existingSecret: r2d2-auth
# Kuma SQLite on Longhorn — single replica, self-contained.
kuma:
persistence:
enabled: true
size: 1Gi
@ -38,7 +55,7 @@ ingress:
className: nginx
# Cluster convention: plain HTTP on *.office.ilab.zone, no TLS/cert-manager.
hosts:
- host: status.r2d2.office.ilab.zone
- host: ops.r2d2.office.ilab.zone
paths:
- path: /
pathType: Prefix

View file

@ -1,15 +1,17 @@
# Default values for r2d2-status.
# Default values for r2d2-status — the Task Force X FMV console.
#
# One pod, two app containers (+ optional VPN sidecar):
# * Uptime Kuma — monitoring engine, listens :3001, SQLite on a PVC.
# * R2D2 Ops console — operator SPA + snapshot/HLS proxy + recorder, :4013.
# Logs into Kuma over localhost and fronts both the SPA and Kuma's status
# pages; the ingress points here.
#
# Environment-specific overrides belong in values.override.yml (helm -f).
# NOTE: replicaCount > 1 requires storage.type=postgres — memory and sqlite
# storage are per-pod and replicas would disagree.
# Kuma keeps monitor config + history in a per-pod SQLite DB, so this chart
# runs a single replica. Scaling out would need shared external storage.
replicaCount: 1
image:
repository: r2d2-status/gatus
tag: latest
pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
@ -22,26 +24,82 @@ serviceAccount:
podAnnotations: {}
podLabels: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
fsGroup: 65534
# Allow unprivileged (UDP-socket) ICMP for icmp:// endpoints — gatus runs as
# 65534 without CAP_NET_RAW. Namespaced sysctl on the k8s safe list.
sysctls:
- name: net.ipv4.ping_group_range
value: "65534 65534"
# Kuma and the ops recorder both run as root and write to their volumes, so no
# non-root / read-only-rootfs hardening here.
podSecurityContext: {}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
# Admin credentials the Ops console uses to log into Kuma (server-side only —
# the browser never sees them). These MUST match the admin user seeded into
# Kuma (see .settings/seed). Source from a Secret in any real deploy.
auth:
# Existing Secret with keys ADMIN_USER and ADMIN_PASS. Preferred.
existingSecret: ""
# Fallback: the chart creates a Secret from these (avoid committing them).
adminUser: ""
adminPass: ""
# --- Uptime Kuma (monitoring engine) --------------------------------------
kuma:
image:
repository: louislam/uptime-kuma
tag: "2"
pullPolicy: IfNotPresent
port: 3001
# SQLite lives on a persistent volume mounted at /app/data so monitor config
# and heartbeat history survive restarts. Longhorn in the office cluster.
persistence:
enabled: true
size: 1Gi
storageClass: ""
existingClaim: ""
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 512Mi
# --- R2D2 Ops console (operator SPA + media proxy + recorder) --------------
opsConsole:
image:
repository: r2d2-status/ops-console
tag: latest
pullPolicy: IfNotPresent
port: 4013
# Interface the console binds inside the pod; the Service/ingress front it.
bind: 0.0.0.0
# Shared secret required on every mutating POST (x-ops-secret header). MUST be
# set before the console is reachable off-cluster. Source from a Secret.
secret:
# Existing Secret with key OPS_SECRET. Preferred.
existingSecret: ""
# Fallback: the chart creates a Secret from this value (avoid committing it).
value: ""
# Extra environment for the console (name: value), e.g. SNAP_HOST, HLS_ALLOW,
# LIVENESS_POLL_MS, REC_FPS. See .settings/ops/serve.mjs for the full list.
env: {}
# Persistent storage for recorded clips/snapshots (mounted as REC_ROOT).
recordings:
enabled: false
size: 20Gi
storageClass: ""
existingClaim: ""
mountPath: /recordings
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 512Mi
service:
type: ClusterIP
port: 80
# The ops console is the primary entrypoint (fronts the SPA + status pages).
port: 4013
# Kuma's own dashboard is exposed too, for admin / port-forward access.
kumaPort: 3001
# Optional extra LoadBalancer service (<fullname>-lb), e.g. for kube-vip.
loadBalancer:
enabled: false
@ -53,29 +111,17 @@ ingress:
className: ""
annotations: {}
hosts:
- host: status.r2d2.office.ilab.zone
- host: ops.r2d2.office.ilab.zone
paths:
- path: /
pathType: Prefix
tls: []
# - secretName: r2d2-status-tls
# hosts: [status.example.org]
# - secretName: r2d2-ops-tls
# hosts: [ops.r2d2.office.ilab.zone]
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 256Mi
logLevel: INFO
# Extra environment variables injected into the gatus container (name: value).
env: {}
# NetBird sidecar — joins the pod to the innovationhub VPN mesh so gatus can
# monitor 100.85.x.x peers. Authenticates with a server setup key (no PAT).
# Pattern mirrors the holovids/nodered fleet sidecars in this cluster.
# NetBird sidecar — joins the pod to the innovationhub VPN mesh so Kuma's probes
# and the ops snapshot/HLS proxies can reach 100.85.x.x feed hosts. Authenticates
# with a server setup key (no PAT). Mirrors the holovids/nodered fleet sidecars.
netbird:
enabled: false
image: netbirdio/netbird:latest
@ -88,7 +134,7 @@ netbird:
setupKey: ""
mtu: "1280"
# DNS stays with the cluster (fleet convention) — address VPN peers by
# their 100.85.x.x IPs in endpoint URLs.
# their 100.85.x.x IPs in monitor / feed URLs.
resources:
requests:
cpu: 10m
@ -96,811 +142,18 @@ netbird:
limits:
memory: 128Mi
storage:
# memory | sqlite | postgres
type: memory
# sqlite only — persistent volume mounted at /data
persistence:
enabled: true
size: 1Gi
storageClass: ""
existingClaim: ""
# postgres only — connection string is injected as DATABASE_URL
postgres:
# Name of an existing Secret containing key DATABASE_URL. Preferred.
existingSecret: ""
# Fallback: the chart creates a Secret from this value (avoid committing it).
# e.g. postgres://user:pass@host:5432/gatus?sslmode=require
connectionString: ""
# Gatus configuration (endpoints, alerting, ui, ...). The storage block is
# rendered by the chart from .Values.storage — do not add one here.
config: |
ui:
title: R2D2-Status
header: R2D2-Status
endpoints:
- name: R2D2
group: r2d2
url: "https://r2d2.office.ilab.zone"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 1000"
- name: Projector
group: r2d2
url: "https://projector.r2d2.office.ilab.zone/restreaming/configuration"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: Replay
group: r2d2
url: "https://replay.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: Holocron
group: r2d2
url: "https://holocron.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: Probe
group: r2d2
url: "https://flora.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: Holonet
group: r2d2
url: "https://mqtt-explorer.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: COP
group: r2d2
url: "https://sw.r2d2.office.ilab.zone/sw/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: Farsight
group: r2d2
url: "https://farsight.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
# Restreamer by LAN IP (r2d2-restreamer.innovationhub.vpn resolves only
# inside the VPN). No cert condition: plain-http URL.
- name: Restreamer (IP)
group: r2d2
url: "http://192.168.3.39:8080/"
interval: 5m
conditions:
- "[STATUS] == 200"
# Projector -> Shared in COP -> Restreamer Endpoints - UDP -> HLS Monitor Feeds
# Video panels are checked every 30 minutes.
- name: Summit 2026
group: summit-2026
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/grp-mr0o1nwk-h6vk22"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: EASTMED
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/p/MwQ7Ayd6SdWH178sRTnm_g"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TF-X CENTMED
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/grp-mqrtdo3q-3kadcz"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TF-X BALTIC
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/grp-mqs4kvsm-x5z68g"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: North Atlantic
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/grp-mqp4kvsm-x9z61g"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: North Sea
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/grp-mqa4kvsm-x1a28g"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TF-X Video Tests
group: tfx-video
url: "https://projector.r2d2.office.ilab.zone/restreaming/groups/p/TmKVSt-lknMHkrL1SYQ8jw"
interval: 30m
conditions:
- "[STATUS] == 200"
# TFX Video - ITA (VPN mesh peer — needs the netbird sidecar enrolled)
- name: TF-X ITA Media Server
group: etl
url: "icmp://100.85.225.183"
interval: 5m
conditions:
- "[CONNECTED] == true"
# Video feeds — generated from config/video/holovids-2026-07-05T06-43-26.csv
# HLS manifests served from the restreamer's in-memory FS (NetBird mesh IP —
# needs the netbird sidecar enrolled). A failed/stopped feed returns 404.
- name: CHN.DRAGF01
group: videos
url: "http://100.85.50.251:8080/memfs/6688afec-beb1-5590-96f0-8fe5fd9bf2fa.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: CHN.HOLYB01
group: videos
url: "http://100.85.50.251:8080/memfs/504681b0-f105-5212-b327-2b3a9a4c2a7f.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: CHN.MAVIC01
group: videos
url: "http://100.85.50.251:8080/memfs/0f7ab7ea-ac76-5e6f-8341-bfce498cee68.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: CHN.MT35001
group: videos
url: "http://100.85.50.251:8080/memfs/94235d82-745b-5332-85d8-e8c57e4f488e.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DNK BLZ 122
group: videos
url: "http://100.85.50.251:8080/memfs/8a381db7-d5ef-4609-b46d-13dda0c9a3d2.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DNK BLZ121 FLIR
group: videos
url: "http://100.85.50.251:8080/memfs/6f3ec590-9a52-487e-80ff-29973ba2f9e4.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DNK BLZ122 FLIR
group: videos
url: "http://100.85.50.251:8080/memfs/a45f3a09-94e7-4924-be38-eaaff82a64be.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DNK BZL121
group: videos
url: "http://100.85.50.251:8080/memfs/f8f03b50-4e5b-48cd-8a9c-e76bd5f1d621.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DNK.RQ35001
group: videos
url: "http://100.85.50.251:8080/memfs/6bdf1260-e9a2-522d-886d-423c1b862af6.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: DUE.UXV
group: videos
url: "http://100.85.50.251:8080/memfs/2b9150d2-82b5-478a-9cfd-e3a69cf2a039.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ESP.ALPHA01
group: videos
url: "http://100.85.50.251:8080/memfs/4a8cdc4f-ca33-5d9a-ba78-c14a339a368b.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ESP.ALPHA02
group: videos
url: "http://100.85.50.251:8080/memfs/6742c002-2d0c-548d-b344-7a091ca029ac.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: GRC Heron
group: videos
url: "http://100.85.50.251:8080/memfs/9dd371ab-6670-4f08-a5fb-d53c3e0f7694.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.ABEUH01
group: videos
url: "http://100.85.50.251:8080/memfs/86ee3417-d7c3-56d3-9daa-64676abb0b89.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.AWHER01
group: videos
url: "http://100.85.50.251:8080/memfs/51f39678-2a97-53f6-884e-6f6738124982.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.CEMAS01
group: videos
url: "http://100.85.50.251:8080/memfs/8b9f9a52-f223-5f8b-bf51-dd44a88fc1f0.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.CEMAS03
group: videos
url: "http://100.85.50.251:8080/memfs/239b9051-2fee-5976-b5e7-911d30262785.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.COUNT01
group: videos
url: "http://100.85.50.251:8080/memfs/a2ee80df-c9a1-5159-b79c-ac73eb7133bc.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.DRRES01
group: videos
url: "http://100.85.50.251:8080/memfs/f7fdcfd9-929b-5be3-9d92-5caf41ec9b59.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.MTS5E01
group: videos
url: "http://100.85.50.251:8080/memfs/da8bef05-2a78-543c-bd1e-8bdcd9aa8f40.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.OMEGA01
group: videos
url: "http://100.85.50.251:8080/memfs/31c2cd50-1160-5b03-9b2f-a69e7a952f18.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.Predator (5079)
group: videos
url: "http://100.85.50.251:8080/memfs/48828507-83cc-4238-9b0f-af9123b73ce7.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RACER01
group: videos
url: "http://100.85.50.251:8080/memfs/aee8d1c3-f5cc-5f6f-bd54-697937a4801b.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RACER06
group: videos
url: "http://100.85.50.251:8080/memfs/a177d811-e46a-51f4-8cfb-adf1e7380e5c.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON01 (ch5001)
group: videos
url: "http://100.85.50.251:8080/memfs/9e7b3e66-6494-5033-9878-602719fbec60.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON01 (ch5045)
group: videos
url: "http://100.85.50.251:8080/memfs/4d97b73b-9a18-53ad-8743-4903b69f24d1.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON02
group: videos
url: "http://100.85.50.251:8080/memfs/5b34da6d-339a-5941-b4cd-c6d7266c9b66.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON05
group: videos
url: "http://100.85.50.251:8080/memfs/49d55ad3-e896-58e3-9c26-a3488dbcd229.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON06
group: videos
url: "http://100.85.50.251:8080/memfs/10aae890-870e-5375-ada4-ffc15751d4bd.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON07
group: videos
url: "http://100.85.50.251:8080/memfs/98c5ee9a-d4ba-53e8-bf12-dc23977648d1.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON09
group: videos
url: "http://100.85.50.251:8080/memfs/c41ee390-89bb-5442-95fd-46024d7d592a.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON10
group: videos
url: "http://100.85.50.251:8080/memfs/ff0496a8-d6dc-5048-b27b-7f3605a1fcb3.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RADON11
group: videos
url: "http://100.85.50.251:8080/memfs/51378b62-b6f7-53c5-87ed-4e5b24c4d177.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RAVEN406
group: videos
url: "http://100.85.50.251:8080/memfs/6442aeba-0b8d-55d1-a579-64540e1dc0d6.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.RUOTA01
group: videos
url: "http://100.85.50.251:8080/memfs/138ba8d9-3aea-5067-9030-cff1d36987db.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SAUTO01
group: videos
url: "http://100.85.50.251:8080/memfs/6d46497d-af44-55b6-a166-0fc53624a12e.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SAUTO02
group: videos
url: "http://100.85.50.251:8080/memfs/8761f463-8c61-5b32-9231-c3732a13a1f1.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SEARP01
group: videos
url: "http://100.85.50.251:8080/memfs/9478f3eb-84cf-5866-a3cf-fb67c30f0d9c.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SHERP01
group: videos
url: "http://100.85.50.251:8080/memfs/662c547d-8748-5d7a-b1ca-6cea71a01795.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SKYMI01
group: videos
url: "http://100.85.50.251:8080/memfs/27891ff4-bca5-5d6f-b22d-ce679500cbff.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SRX4001
group: videos
url: "http://100.85.50.251:8080/memfs/07d356cb-7a03-5b9f-9fea-77d946fd6142.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.SRX4002
group: videos
url: "http://100.85.50.251:8080/memfs/99384366-7ba9-5e94-bc80-c51a8143ff3a.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.ULISS01
group: videos
url: "http://100.85.50.251:8080/memfs/b6e61209-0302-5583-a760-9f0f2b71f3ea.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.VIKIN01
group: videos
url: "http://100.85.50.251:8080/memfs/6cd41f3f-5642-5ba8-b0ad-68e0a534d452.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.XENON01
group: videos
url: "http://100.85.50.251:8080/memfs/cdc7567b-b137-5cd2-a584-7b23386bb2c2.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.XENON03
group: videos
url: "http://100.85.50.251:8080/memfs/84949a3a-9952-50b2-8193-c7ba5e6c5442.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: ITA.XHEAV01
group: videos
url: "http://100.85.50.251:8080/memfs/d58f87d6-4a21-5022-8995-962b360e8bbf.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: live
group: videos
url: "http://100.85.50.251:8080/memfs/test-udp5000.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: LocalLoopTest LowRes
group: videos
url: "http://100.85.50.251:8080/memfs/b2a4e1e7-5ec2-464b-bd75-a080f8282b71.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: LTU Penguin
group: videos
url: "http://100.85.50.251:8080/memfs/0c743db8-46d1-4c2d-8726-cb46692a0ead.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: LVA.FOG0001
group: videos
url: "http://100.85.50.251:8080/memfs/ff4f2d9d-f36d-5686-b6da-eea2db33c97c.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: NLD Otter
group: videos
url: "http://100.85.50.251:8080/memfs/4819f4e6-e936-49c9-9224-7a92393d8d53.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: POL Test1
group: videos
url: "http://100.85.50.251:8080/memfs/7e17d681-a87f-4040-9038-d42a5e75167c.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TFX (5000)
group: videos
url: "http://100.85.50.251:8080/memfs/2d049b93-d734-5986-9f07-30bd328ede64.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TFX (5000) ITA
group: videos
url: "http://100.85.50.251:8080/memfs/33ec5472-dbd7-43fe-8844-0ceda3253cce.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Baykar
group: videos
url: "http://100.85.50.251:8080/memfs/e8ed7c58-cec9-4186-9066-fb9d45589868.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Marlin
group: videos
url: "http://100.85.50.251:8080/memfs/c239e81f-6fef-4746-8fc5-309a32f11632.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Salvo
group: videos
url: "http://100.85.50.251:8080/memfs/fad5a90b-c1ad-4561-b92e-f94df4362f12.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Sancar
group: videos
url: "http://100.85.50.251:8080/memfs/71696adc-2894-4409-9115-c5985fd001bc.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Tusas
group: videos
url: "http://100.85.50.251:8080/memfs/92c9c4e6-a01b-43ff-b23e-8f6aa52c9c8c.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: TUR Ulaq
group: videos
url: "http://100.85.50.251:8080/memfs/5eda5cc6-cc46-4bcb-914b-aa2921e10f58.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.ARABF01
group: videos
url: "http://100.85.50.251:8080/memfs/126b16a1-3420-5702-b2cc-c78a08f99c86.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.GARC001
group: videos
url: "http://100.85.50.251:8080/memfs/58cd16e4-f9fd-5b52-8687-16c2afd4f4f8.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.GARC002
group: videos
url: "http://100.85.50.251:8080/memfs/3147a219-417f-5c52-a628-4116a94cf7f2.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.LIGHF01
group: videos
url: "http://100.85.50.251:8080/memfs/0b991665-9a0d-5710-82a5-32a7719cd18a.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.VBAT001
group: videos
url: "http://100.85.50.251:8080/memfs/1f86b69f-84a1-5a18-be2c-f3d015120c66.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
- name: USA.X10D001
group: videos
url: "http://100.85.50.251:8080/memfs/4d968322-c05b-51ea-bdb5-a286beb3e072.m3u8"
interval: 30m
conditions:
- "[STATUS] == 200"
# NodeRed fleet — generated from config/node-red-instances.tsv
- name: staging
group: nodered
url: "https://nodered.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr1 (AIS Ingest)
group: nodered
url: "https://nr1.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr2 (AIS Enrichment)
group: nodered
url: "https://nr2.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr3 (ADSB Ingest)
group: nodered
url: "https://nr3.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr4 (Sitaware Telemetry)
group: nodered
url: "https://nr4.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr5 (Sitaware Contacts)
group: nodered
url: "https://nr5.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr6 (External Feeds)
group: nodered
url: "https://nr6.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr7 (Medusa Ingest)
group: nodered
url: "https://nr7.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr8 (Medusa Fusion)
group: nodered
url: "https://nr8.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr11 (TFX-ITA)
group: nodered
url: "https://nr11.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr12 (TFX-DNK)
group: nodered
url: "https://nr12.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr13 (TFX-TUR)
group: nodered
url: "https://nr13.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr14 (TFX-SWE)
group: nodered
url: "https://nr14.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr15 (TFX-NLD)
group: nodered
url: "https://nr15.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr16 (TFX-GBR)
group: nodered
url: "https://nr16.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr17 (TFX-USA)
group: nodered
url: "https://nr17.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr18 (TFX-LTU/GRC)
group: nodered
url: "https://nr18.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr19 (TFX-Arctic(CMRE)/NorthAtlantic(PRT))
group: nodered
url: "https://nr19.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
- name: nr20 (General/Relay)
group: nodered
url: "https://nr20.r2d2.office.ilab.zone/"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 48h"
## Internal Endpoints
- name: DNS-query
group: internal
url: "8.8.8.8"
interval: 5m
dns:
query-name: "office.ilab.zone"
query-type: "A"
conditions:
- "[BODY] == pat(*.*.*.*)"
- "[DNS_RCODE] == NOERROR"
# Probes hit the ops console — if it's up, the SPA and the Kuma proxy are up.
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
path: /
port: ops
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 3
path: /
port: ops
initialDelaySeconds: 5
periodSeconds: 10
nodeSelector: {}