monitoring(grafana): repoint InfluxDB datasource at in-cluster server
VM 108 (the legacy InfluxDB at influxdb.srv.renner.uno:10.2.40.16) is
unreachable — no ICMP, no SSH, no port 8086. K8s Grafana's InfluxDB
datasource has been silently broken since the in-cluster InfluxDB
came online (commit 1daaa6f, 2026-05-05). The heatpump-roi dashboard
and any historical HA panel that queries InfluxDB are dead until this
repoint lands.
Datasource URL: http://influxdb-influxdb2.influxdb.svc.cluster.local:8086.
The legacy SOPS-stored token (`grafana-influxdb-token.sops.yaml`) is
useless against the in-cluster bolt store. Replaced with a seed Job
that mirrors the existing `influxdb-ha-token` pattern: ServiceAccount
in influxdb ns + cross-namespace Role on the `grafana-influxdb-token`
Secret in monitoring ns + Job that creates a read-only auth on the
suedstr28 bucket and writes the token to that Secret. The key name
inside the Secret stays `INFLUXDB_TOKEN` so the existing
`envFromSecrets` reference in the helmrelease keeps working.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
apiVersion: ENC[AES256_GCM,data:UJo=,iv:dWPZY9IPOwP/wz7NNHWgNLqcemZ7SF5vTLGkLAIVtMw=,tag:/mUiJ+1bSvM1Q+1Z2MAoAQ==,type:str]
|
||||
kind: ENC[AES256_GCM,data:2evJBSao,iv:GV5uMMGXkj4unsrX6eSDSnXztVJvO3PH7KysfZVZf9Y=,tag:jL1ouzE3T6utlUgWe5xRGA==,type:str]
|
||||
metadata:
|
||||
name: ENC[AES256_GCM,data:yBHEPANSWoXEFtd5/hJaUhPOtGNtUg==,iv:IJVco8HWDAEpkS0R7Lw1YDI374cfG+5FIcr81jg6JUA=,tag:cmz68dU++5sqoPoHsTfBJQ==,type:str]
|
||||
namespace: ENC[AES256_GCM,data:a31jcEaz5JIKSg==,iv:qiyyEy3CNgEbTIrjMIt5wurQWNsXp2Y32TIZ13pNFWM=,tag:hqtHHq+vdxOs8evHkZs2Fw==,type:str]
|
||||
type: ENC[AES256_GCM,data:VE7pZ34m,iv:I22j9ZxbieeHiQwrXiS9xpHNzp49Yu2g+kbLk8CM5HU=,tag:WyaAjY6fz3RJK+ScAlkS8A==,type:str]
|
||||
stringData:
|
||||
INFLUXDB_TOKEN: ENC[AES256_GCM,data:MhpHqSIk3Nea7msIxzQmvEuFjChNIDfnRpHge4WNVVV3YWeecslMk7cMvRSUBSb0zQ9YYyCKWlnoM7Z+45mfpDDiYB/cnOx1DGXDPGNA8nb6wqJZkbRciA==,iv:xdzC52H9ajkCC2kyXsrlRoBBIYfZ9qD41CrPCntxPTA=,tag:e1Kdix1oX90vVhAp0eq7yQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1yqjvqkwwwxdj7mr546zfs5ckzuwndp69ya2n2drd4vypwns8w4ys04qfy3
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQZXBHaVpLUVJtOWJCaTJG
|
||||
cDg3SUR1QUhDb1BhaGtIWG9tdGlFRit4L3hRCi9LNHdNdS95RHFmQTNNYk43OEJV
|
||||
WGtNd1RuL0N6QTFvZVMvdHAzbmx1b2cKLS0tIHpEeStVWVI5MFlENDE5VXV4RE80
|
||||
Y2hNRHpzeTVEZmhPUjhzbklvdVR4UGcKBfngE1xQY14LM03nu1q905JrLkG3SVrX
|
||||
qyGIEe5xjxTLY4WCu5jfKAEkLmjTwFTGJLg+0F0J+S2MmXyyigBNiQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-04-23T12:57:29Z"
|
||||
mac: ENC[AES256_GCM,data:LsMf8qJh519Ylg62jmNmMLt98db8b5S6tvJnxZgpLo9es8jux5g0f75loWTIqzsXL6T7nglWuTp2ouwX4YCgiqTjHPSjJ94ACLpeiFEmjY23gGHtZP1PY1dXZ69OwRJNNmJbEYtopw/rxO/J54MhYi28IL1MDRuwdU/ZttSlqH8=,iv:tgRMH6F4HCHctmAa8UAPnlGUojl+GN3vbDflPbhwxuI=,tag:Ol9YUiEbXSJL+49Klhh/lg==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
@@ -183,14 +183,16 @@ spec:
|
||||
isDefault: false
|
||||
jsonData:
|
||||
httpMethod: POST
|
||||
# InfluxDB on VM 108 — Home Assistant is the sole writer. K8s
|
||||
# Grafana consumes the live VM 108 endpoint until HA migrates
|
||||
# (writer cut-over + datasource flip to cluster-internal deferred
|
||||
# to the HA migration plan).
|
||||
# In-cluster InfluxDB (chart `influxdb-influxdb2`). Both HA (write)
|
||||
# and Grafana (read) hit this directly via Service DNS. The
|
||||
# `grafana-influxdb-token` Secret is created by the seed Job
|
||||
# `influxdb-grafana-token` (kubernetes/seed/influxdb/grafana-
|
||||
# token-job.yaml), which mints a read-only auth on the
|
||||
# suedstr28 bucket every fresh deploy.
|
||||
- name: InfluxDB
|
||||
uid: influxdb
|
||||
type: influxdb
|
||||
url: http://influxdb.srv.renner.uno:8086
|
||||
url: http://influxdb-influxdb2.influxdb.svc.cluster.local:8086
|
||||
access: proxy
|
||||
isDefault: false
|
||||
jsonData:
|
||||
|
||||
@@ -2,7 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- grafana-oauth.sops.yaml
|
||||
- grafana-influxdb-token.sops.yaml
|
||||
- garage-metrics-token.sops.yaml
|
||||
- alertmanager-smtp.sops.yaml
|
||||
- pve-exporter-config.sops.yaml
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
# Mirror of ha-token-job.yaml but creates a read-only auth for K8s
|
||||
# Grafana on the suedstr28 bucket, and stashes the token as the
|
||||
# `grafana-influxdb-token` Secret in the monitoring namespace. Replaces
|
||||
# the previously SOPS-stored token that targeted the (now-retired) VM
|
||||
# 108 InfluxDB and no longer matches the in-cluster server's bolt store.
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: influxdb-grafana-token
|
||||
namespace: influxdb
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: grafana-influxdb-token-writer
|
||||
namespace: monitoring
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create"]
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
resourceNames: ["grafana-influxdb-token"]
|
||||
verbs: ["get", "update", "patch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: grafana-influxdb-token-writer
|
||||
namespace: monitoring
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: influxdb-grafana-token
|
||||
namespace: influxdb
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: grafana-influxdb-token-writer
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: influxdb-grafana-token
|
||||
namespace: influxdb
|
||||
annotations:
|
||||
kustomize.toolkit.fluxcd.io/force: enabled
|
||||
spec:
|
||||
backoffLimit: 6
|
||||
ttlSecondsAfterFinished: 86400
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
serviceAccountName: influxdb-grafana-token
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
runAsNonRoot: false
|
||||
initContainers:
|
||||
- name: wait-for-influxd
|
||||
image: influxdb:2.7.4
|
||||
env:
|
||||
- { name: INFLUX_HOST, value: http://influxdb-influxdb2.influxdb.svc.cluster.local:8086 }
|
||||
- { name: INFLUX_ORG, value: renner }
|
||||
- name: INFLUX_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef: { name: influxdb-bootstrap, key: admin-token }
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
until influx ping >/dev/null 2>&1; do
|
||||
echo "[$(date -u +%H:%M:%S)] waiting for $INFLUX_HOST..."
|
||||
sleep 5
|
||||
done
|
||||
until influx bucket list >/dev/null 2>&1; do
|
||||
echo "[$(date -u +%H:%M:%S)] API up; waiting for bootstrap admin token..."
|
||||
sleep 5
|
||||
done
|
||||
echo "[$(date -u +%H:%M:%S)] $INFLUX_HOST ready and authenticated"
|
||||
containers:
|
||||
- name: create
|
||||
image: influxdb:2.7.4
|
||||
env:
|
||||
- { name: INFLUX_HOST, value: http://influxdb-influxdb2.influxdb.svc.cluster.local:8086 }
|
||||
- { name: INFLUX_ORG, value: renner }
|
||||
- { name: INFLUX_BUCKET, value: suedstr28 }
|
||||
- { name: TOKEN_DESC, value: grafana read }
|
||||
- { name: TARGET_NS, value: monitoring }
|
||||
- { name: TARGET_SECRET, value: grafana-influxdb-token }
|
||||
- name: INFLUX_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef: { name: influxdb-bootstrap, key: admin-token }
|
||||
command:
|
||||
- bash
|
||||
- -c
|
||||
- |
|
||||
set -euo pipefail
|
||||
log() { printf '[%s] %s\n' "$(date -u +%H:%M:%S)" "$*"; }
|
||||
|
||||
apt-get update -qq
|
||||
apt-get install -y --no-install-recommends curl jq ca-certificates >/dev/null
|
||||
KV=$(curl -fsSL https://dl.k8s.io/release/stable.txt)
|
||||
curl -fsSL "https://dl.k8s.io/release/$KV/bin/linux/amd64/kubectl" -o /usr/local/bin/kubectl
|
||||
chmod +x /usr/local/bin/kubectl
|
||||
|
||||
BUCKET_ID=$(influx bucket list --name "$INFLUX_BUCKET" --json | jq -r '.[0].id')
|
||||
[ -n "$BUCKET_ID" ] && [ "$BUCKET_ID" != "null" ] || {
|
||||
log "ERROR: bucket $INFLUX_BUCKET not found"
|
||||
exit 1
|
||||
}
|
||||
log "bucket $INFLUX_BUCKET id=$BUCKET_ID"
|
||||
|
||||
EXISTING=$(influx auth list --json \
|
||||
| jq -r --arg d "$TOKEN_DESC" '.[] | select(.description == $d) | .token' \
|
||||
| head -1)
|
||||
if [ -n "$EXISTING" ]; then
|
||||
TOKEN="$EXISTING"
|
||||
log "reusing existing auth ($TOKEN_DESC)"
|
||||
else
|
||||
# Read-only on the bucket. Grafana queries via Flux which
|
||||
# only reads.
|
||||
TOKEN=$(influx auth create \
|
||||
--org "$INFLUX_ORG" \
|
||||
--description "$TOKEN_DESC" \
|
||||
--read-bucket "$BUCKET_ID" \
|
||||
--json | jq -r '.token')
|
||||
[ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] || {
|
||||
log "ERROR: influx auth create produced empty token"
|
||||
exit 1
|
||||
}
|
||||
log "created new auth ($TOKEN_DESC)"
|
||||
fi
|
||||
|
||||
# K8s Grafana's envFromSecret reads the key as
|
||||
# INFLUXDB_TOKEN (set in the chart values); use the same
|
||||
# key name so a single Secret-rotate refreshes the
|
||||
# template var.
|
||||
log "writing $TARGET_NS/$TARGET_SECRET via apply"
|
||||
kubectl -n "$TARGET_NS" create secret generic "$TARGET_SECRET" \
|
||||
--from-literal=INFLUXDB_TOKEN="$TOKEN" \
|
||||
--dry-run=client -o yaml \
|
||||
| kubectl apply -f -
|
||||
|
||||
log "Done."
|
||||
@@ -4,3 +4,4 @@ resources:
|
||||
- bootstrap-secret.sops.yaml
|
||||
- helmrelease.yaml
|
||||
- ha-token-job.yaml
|
||||
- grafana-token-job.yaml
|
||||
|
||||
Reference in New Issue
Block a user