Compare commits

...

6 Commits

Author SHA1 Message Date
Ben Vincent ffcf646d87 Rework jellyfin-ha into a true-HA StatefulSet deployment
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline failed
Turn the single-replica jellyfin-ha app into a proper high-availability
deployment so the fork's Redis-coordinated distributed transcoding and
PostgreSQL main database can actually be exercised.

- Replace the Deployment with a 2-replica StatefulSet for stable pod
  identity; set JELLYFIN_INSTANCE_ID from metadata.name (the fork's Redis
  transcode-lease owner id), add soft podAntiAffinity and a PDB
  minAvailable 1.
- Move the main Jellyfin DB to PostgreSQL via a CloudNativePG trio
  (3-instance Cluster, PgBouncer Pooler, Ceph RGW barman backups) mirroring
  the litellm pattern; an init container writes database.xml selecting the
  fork's Jellyfin-PostgreSQL provider and the DSN is composed from the
  CNPG-generated app secret pointed at the pooler.
- Share /config on an RWX cephfs PVC across replicas; keep /cache per-pod
  via a volumeClaimTemplate.
- Fix the transcode mount to the fork's real path /config/transcodes on the
  RWX PVC (raid5) so a surviving pod can resume the segments of the pod it
  takes over.
- Add Intel iGPU hardware transcoding via the gpu.intel.com/i915 device
  plugin resource plus render/video supplemental groups.
- Switch the Service to sessionAffinity ClientIP to reduce transcode churn.
- Disable UDP auto-discovery. Library scans still run on every replica; a
  single-scanner leader election is a planned follow-up.
2026-08-10 23:27:36 +10:00
Ben Vin a29fa5b8cc Add jellyfin (HA fork) app under a new media project
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
Deploys the jellyfin-ha fork (git.unkin.net/unkin/jellyfin-ha) to au-syd1
via ArgoCD, under a dedicated media AppProject/ApplicationSet rather than
extending platform.

- New media AppProject + media-apps ApplicationSet (watches
  apps/overlays/*/jellyfin); registered in the argocd kustomizations
- apps/base/jellyfin: namespace, deployment (single replica to start),
  service, in-namespace Redis (transcode session store), gateway + httproute
  at jellyfin.k8s.syd1.au.unkin.net
- Storage: RWO config (cephrbd), RWX transcode scratch and RWX media
  library (cephfs) per the HA fork's pod-takeover requirement
- au-syd1 overlay
2026-07-05 22:32:24 +10:00
unkinben 391197ad1c Merge pull request 'schemas: add grafana.integreatly.org CRD schemas' (#236) from benvin/grafana-schemas into main 2026-07-05 22:22:19 +10:00
unkinben c17bbda89b schemas: add grafana.integreatly.org CRD schemas
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
Generated from the grafana-operator v5.24.0 CRDs (added in the previous
PR) so `make kubeconform` can validate the Grafana / GrafanaDashboard /
GrafanaDatasource / GrafanaFolder CRs introduced by the grafana instance
PR. Mirrors ci/generate-schemas.sh output for the grafana CRD group.
2026-07-05 22:19:40 +10:00
unkinben 0f6c9e5502 Merge pull request 'grafana-system: deploy grafana-operator' (#235) from benvin/grafana-operator into main 2026-07-05 22:18:57 +10:00
unkinben 5f8f2b1c70 observability: migrate VictoriaMetrics to operator CRDs + Consul SD (#234)
## Why
The k8s au-syd1 VictoriaMetrics stack ran as two helm charts and only scraped in-cluster targets. The victoria-metrics-operator already runs in vm-system, so this moves the stack onto operator-managed CRDs. That unlocks VMServiceScrape/VMPodScrape (auto-converted from Prometheus ServiceMonitors, used by a follow-up PR) and adds Consul service discovery so the cluster scrapes the **same puppet-prod targets** as the puppet vmagent. Also shrinks vmstorage 3 → 2 (Ceph-backed, replicationFactor 2).

## Changes
- Add **VMCluster `main`**: vmstorage 2 replicas (cephrbd-fast-delete 200Gi, 180d retention, replicationFactor 2), vminsert/vmselect 2 replicas + HPA (2–10, 60% cpu).
- Add **VMAgent `main`**: retains the kubernetes SD jobs (apiservers/nodes/cadvisor), `selectAllByDefault` for VMServiceScrape/VMPodScrape, and a **Consul SD job** against `consul.service.consul` (resolves to the puppet Consul from pods) replicating the puppet vmagent relabels — keep tag `metrics`, `__scheme__` from `metrics_scheme`, `job` from `metrics_job`. TLS is **verified against the reflected `vault-ca-cert`** (no insecure skip-verify).
- Expose vmselect/vminsert/vmagent via **Gateway API** (traefik-internal Gateway + HTTPRoute, http→https redirect), same hostnames.
- Remove the two helm charts, their values files, and vendored charts.

## Notes
- Data wipe on cutover is acceptable (confirmed) — old helm PVCs can be deleted.
- Verify at rollout: pods resolve `*.main.unkin.net` node FQDNs (needed for CA SAN match on scrape targets); `/targets` shows `job=consul`.

Reviewed-on: #234
Co-authored-by: Ben Vincent <ben@unkin.net>
Co-committed-by: Ben Vincent <ben@unkin.net>
2026-07-05 22:17:32 +10:00
42 changed files with 13607 additions and 301 deletions
+45
View File
@@ -0,0 +1,45 @@
---
# Ceph RGW (S3) backup target for the jellyfin CNPG cluster, provisioned by the
# in-estate cephrgw-operator: one dedicated bucket + owner user. CNPG reads the
# S3 credential Secret from its own namespace.
apiVersion: ceph.unkin.net/v1alpha1
kind: ObjectStoreUser
metadata:
name: cnpg-jellyfin-backup
namespace: jellyfin
spec:
displayName: "CNPG backup owner (jellyfin)"
uid: cnpg-jellyfin-backup
maxBuckets: 5
secretName: cnpg-jellyfin-backup-s3
retainOnDelete: true
---
apiVersion: ceph.unkin.net/v1alpha1
kind: Bucket
metadata:
name: cnpg-jellyfin
namespace: jellyfin
spec:
placementTarget: ec
bucketName: cnpg-jellyfin
ownerRef: cnpg-jellyfin-backup
versioning: false
tags:
app: jellyfin
purpose: cnpg-backup
retainOnDelete: true
---
# Nightly base backup on top of always-on WAL archiving. Scheduled off-peak and
# staggered from the other CNPG clusters (6-field cron, seconds first).
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: cnpg-jellyfin-nightly
namespace: jellyfin
spec:
schedule: "0 35 3 * * *"
immediate: false
backupOwnerReference: self
method: barmanObjectStore
cluster:
name: jellyfin-postgres
+119
View File
@@ -0,0 +1,119 @@
---
# Main Jellyfin database. The jellyfin-ha fork's experimental EF Core provider
# moves the entire Jellyfin DB (incl. library items) off SQLite into PostgreSQL,
# which is what makes a shared-nothing multi-replica deployment possible. No
# bootstrap secret is given, so CNPG generates the jellyfin-postgres-app secret
# (username/password/dbname) that the StatefulSet composes its DSN from.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: jellyfin-postgres
namespace: jellyfin
spec:
affinity:
podAntiAffinityType: preferred
backup:
retentionPolicy: 30d
barmanObjectStore:
# Dedicated per-cluster Ceph RGW bucket (cephrgw-operator provisions it).
destinationPath: s3://cnpg-jellyfin
endpointURL: https://s3.ceph.unkin.net
endpointCA:
name: vault-ca-cert
key: ca.crt
s3Credentials:
accessKeyId:
name: cnpg-jellyfin-backup-s3
key: AWS_ACCESS_KEY_ID
secretAccessKey:
name: cnpg-jellyfin-backup-s3
key: AWS_SECRET_ACCESS_KEY
serverName: jellyfin
data:
compression: bzip2
jobs: 2
wal:
compression: zstd
maxParallel: 2
bootstrap:
initdb:
database: jellyfin
encoding: UTF8
localeCType: C
localeCollate: C
owner: jellyfin
enablePDB: true
enableSuperuserAccess: false
failoverDelay: 0
# PG 17 — accepted by the fork's Npgsql/EF Core provider (needs PG14+); the
# provider generates its own migrations on first start.
imageName: ghcr.io/cloudnative-pg/postgresql:17-system-trixie
instances: 3
logLevel: info
maxSyncReplicas: 0
minSyncReplicas: 0
monitoring:
customQueriesConfigMap:
- key: queries
name: cnpg-default-monitoring
disableDefaultQueries: false
enablePodMonitor: false
postgresql:
parameters:
archive_mode: "on"
archive_timeout: 5min
dynamic_shared_memory_type: posix
effective_cache_size: 256MB
full_page_writes: "on"
log_destination: csvlog
log_directory: /controller/log
log_filename: postgres
log_rotation_age: "0"
log_rotation_size: "0"
log_truncate_on_rotation: "false"
logging_collector: "on"
max_connections: "200"
max_parallel_workers: "16"
max_replication_slots: "16"
max_worker_processes: "16"
shared_buffers: 128MB
shared_memory_type: mmap
ssl_max_protocol_version: TLSv1.3
ssl_min_protocol_version: TLSv1.3
wal_keep_size: 256MB
wal_level: logical
wal_log_hints: "on"
wal_receiver_timeout: 5s
wal_sender_timeout: 5s
syncReplicaElectionConstraint:
enabled: false
primaryUpdateMethod: restart
primaryUpdateStrategy: unsupervised
probes:
liveness:
isolationCheck:
connectionTimeout: 1000
enabled: true
requestTimeout: 1000
replicationSlots:
highAvailability:
enabled: true
slotPrefix: _cnpg_
synchronizeReplicas:
enabled: true
updateInterval: 30
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: 50m
memory: 512Mi
smartShutdownTimeout: 180
startDelay: 3600
stopDelay: 1800
storage:
resizeInUseVolumes: true
size: 10Gi
storageClass: cephrbd-fast-delete
switchoverDelay: 3600
+36
View File
@@ -0,0 +1,36 @@
---
# PgBouncer pooler in front of the jellyfin-postgres cluster. Jellyfin connects
# here (jellyfin-postgres-pooler:5432) rather than the -rw service so EF Core's
# connection churn is absorbed by the pool.
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
name: jellyfin-postgres-pooler
namespace: jellyfin
spec:
cluster:
name: jellyfin-postgres
instances: 2
pgbouncer:
parameters:
default_pool_size: "50"
max_client_conn: "200"
paused: false
poolMode: session
template:
metadata:
labels:
app: jellyfin-pooler
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- jellyfin-pooler
topologyKey: kubernetes.io/hostname
containers: []
type: rw
+37
View File
@@ -0,0 +1,37 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
labels:
traefik.io/instance: internal
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: jellyfin.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: jellyfin.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.4
name: jellyfin
namespace: jellyfin
spec:
gatewayClassName: traefik-internal
listeners:
- allowedRoutes:
namespaces:
from: Same
hostname: jellyfin.k8s.syd1.au.unkin.net
name: http
port: 80
protocol: HTTP
- allowedRoutes:
namespaces:
from: Same
hostname: jellyfin.k8s.syd1.au.unkin.net
name: https
port: 443
protocol: HTTPS
tls:
certificateRefs:
- group: ""
kind: Secret
name: jellyfin-tls
mode: Terminate
+49
View File
@@ -0,0 +1,49 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-redirect
namespace: jellyfin
spec:
hostnames:
- jellyfin.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: jellyfin
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: jellyfin-route
namespace: jellyfin
spec:
hostnames:
- jellyfin.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: jellyfin
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: jellyfin
port: 8096
weight: 1
matches:
- path:
type: PathPrefix
value: /
+20
View File
@@ -0,0 +1,20 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- cnpg_cluster.yaml
- cnpg_pooler.yaml
- cnpg_backup.yaml
- pvc-config.yaml
- pvc-transcode.yaml
- pvc-media.yaml
- statefulset.yaml
- pdb.yaml
- service.yaml
- redis-deployment.yaml
- redis-pvc.yaml
- redis-service.yaml
- gateway.yaml
- httproute.yaml
+5
View File
@@ -0,0 +1,5 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: jellyfin
+13
View File
@@ -0,0 +1,13 @@
---
# Keep at least one Jellyfin replica serving through voluntary disruptions
# (node drains, rollouts) so active streams can fail over rather than drop.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: jellyfin
namespace: jellyfin
spec:
minAvailable: 1
selector:
matchLabels:
app: jellyfin
+17
View File
@@ -0,0 +1,17 @@
---
# Jellyfin config: metadata images, plugins, subtitles and config XML. Shared
# ReadWriteMany across replicas (all pods read/write the same library metadata);
# the main library DB now lives in PostgreSQL, not here. Retain — this is state.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jellyfin-config
namespace: jellyfin
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 20Gi
storageClassName: cephfs-raid5-retain
volumeMode: Filesystem
+17
View File
@@ -0,0 +1,17 @@
---
# Media library, shared read-many across replicas. Retain — this holds the
# actual media and must survive PVC deletion. Empty on first deploy; populating
# it is out of scope for this app.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jellyfin-media
namespace: jellyfin
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Ti
storageClassName: cephfs-raid6-retain
volumeMode: Filesystem
+18
View File
@@ -0,0 +1,18 @@
---
# Shared transcode scratch. ReadWriteMany is the hard requirement for the HA
# fork: a taking-over pod must read the in-flight HLS segments written by the
# pod it replaces. Scratch data (delete reclaim); raid5 avoids the raid6
# double-parity write penalty on the many small HLS segment writes.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jellyfin-transcode
namespace: jellyfin
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: cephfs-raid5-delete
volumeMode: Filesystem
+66
View File
@@ -0,0 +1,66 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: jellyfin
spec:
replicas: 1
selector:
matchLabels:
app: redis
strategy:
type: Recreate
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
imagePullPolicy: IfNotPresent
command:
- redis-server
- --save
- "20"
- "1"
ports:
- containerPort: 6379
name: redis
protocol: TCP
livenessProbe:
exec:
command:
- redis-cli
- ping
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
exec:
command:
- redis-cli
- ping
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 50m
memory: 128Mi
volumeMounts:
- mountPath: /data
name: data
restartPolicy: Always
volumes:
- name: data
persistentVolumeClaim:
claimName: jellyfin-redis-data
+14
View File
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jellyfin-redis-data
namespace: jellyfin
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: cephrbd-fast-delete
volumeMode: Filesystem
+17
View File
@@ -0,0 +1,17 @@
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: jellyfin
spec:
internalTrafficPolicy: Cluster
ports:
- name: redis
port: 6379
protocol: TCP
targetPort: redis
selector:
app: redis
sessionAffinity: None
type: ClusterIP
+18
View File
@@ -0,0 +1,18 @@
---
apiVersion: v1
kind: Service
metadata:
name: jellyfin
namespace: jellyfin
spec:
internalTrafficPolicy: Cluster
ports:
- name: http
port: 8096
protocol: TCP
targetPort: http
selector:
app: jellyfin
# Pin each client to one replica to reduce transcode-session churn/takeover.
sessionAffinity: ClientIP
type: ClusterIP
+199
View File
@@ -0,0 +1,199 @@
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: jellyfin
namespace: jellyfin
spec:
# HA: two replicas coordinate transcode session ownership through Redis and
# resume each other's HLS segments off the shared RWX transcode PVC. Stable
# pod names (jellyfin-0/1) are the lease owner identity, hence StatefulSet.
replicas: 2
serviceName: jellyfin
podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: jellyfin
template:
metadata:
labels:
app: jellyfin
spec:
securityContext:
# Group-write the shared RWX volumes and grant the render/video groups so
# the runAsUser 1000 process can open the Intel DRI render node injected
# by the device plugin.
fsGroup: 1000
supplementalGroups:
- 44
- 105
- 109
seccompProfile:
type: RuntimeDefault
affinity:
# Spread the two replicas across nodes for node-level HA. Soft so a
# single-GPU-node cluster still schedules both (i915 has 4 shared slots).
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: jellyfin
topologyKey: kubernetes.io/hostname
initContainers:
# Select the fork's experimental PostgreSQL provider by writing
# database.xml before Jellyfin starts. Runs as root to chown into the
# shared config volume; mirrors the fork Helm chart's inject-db-config.
- name: inject-db-config
image: busybox:1.37.0
command:
- sh
- -c
- |
mkdir -p /config/config
chown 1000:1000 /config/config
chmod 775 /config/config
cat > /config/config/database.xml << 'DBEOF'
<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfigurationOptions>
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
<LockingBehavior>NoLock</LockingBehavior>
</DatabaseConfigurationOptions>
DBEOF
chown 1000:1000 /config/config/database.xml
chmod 664 /config/config/database.xml
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 100m
memory: 64Mi
volumeMounts:
- name: config
mountPath: /config
containers:
- name: jellyfin
image: git.unkin.net/unkin/jellyfin-ha:v0.1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8096
protocol: TCP
env:
# Pod identity for the Redis transcode lease owner. The fork reads
# JELLYFIN_INSTANCE_ID (falling back to MachineName); the stable
# StatefulSet pod name gives each replica a unique lease identity so
# takeover can target a dead replica. JELLYFIN_HA_POD_NAME is set for
# parity with the fork Helm chart (nothing currently reads it).
- name: JELLYFIN_INSTANCE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: JELLYFIN_HA_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# Multiple replicas must not each answer UDP auto-discovery.
- name: JELLYFIN_Network__AutoDiscovery
value: "false"
# Config dir must differ from the data root (Jellyfin sanity check).
- name: JELLYFIN_CONFIG_DIR
value: /config/config
# Distributed transcode session store (jellyfin-ha additions).
- name: Jellyfin__TranscodeStore__RedisConnectionString
value: "redis:6379,abortConnect=false"
- name: Jellyfin__TranscodeStore__LeaseDurationSeconds
value: "30"
# PostgreSQL main DB via the CNPG-generated app secret, routed through
# the PgBouncer pooler. Composed with $(VAR) expansion so the password
# is never rendered into the manifest; CNPG passwords are URL-safe.
- name: PGUSER
valueFrom:
secretKeyRef:
name: jellyfin-postgres-app
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: jellyfin-postgres-app
key: password
- name: PGDB
valueFrom:
secretKeyRef:
name: jellyfin-postgres-app
key: dbname
- name: POSTGRES_CONNECTION_STRING
value: "postgresql://$(PGUSER):$(PGPASSWORD)@jellyfin-postgres-pooler:5432/$(PGDB)"
- name: DATABASE_URL
value: "postgresql://$(PGUSER):$(PGPASSWORD)@jellyfin-postgres-pooler:5432/$(PGDB)"
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
requests:
cpu: "1"
memory: 1Gi
gpu.intel.com/i915: "1"
limits:
cpu: "4"
memory: 6Gi
# Intel iGPU (QSV/VA-API) slot. Requesting it pins the pod to a
# GPU-labelled node and injects /dev/dri/renderD* automatically, so
# no /dev/dri hostPath or privileged container is needed. Enable
# QSV/VA-API once in the Jellyfin admin UI; it persists to /config.
gpu.intel.com/i915: "1"
securityContext:
runAsUser: 1000
runAsGroup: 1000
volumeMounts:
- name: config
mountPath: /config
- name: transcode
# Fork's real transcode temp path. RWX so a surviving pod reads the
# in-flight .ts/.m3u8 segments of the pod it takes over. A per-pod
# volume here silently breaks HA takeover.
mountPath: /config/transcodes
- name: cache
mountPath: /cache
- name: media
mountPath: /media
readOnly: true
volumes:
- name: config
persistentVolumeClaim:
claimName: jellyfin-config
- name: transcode
persistentVolumeClaim:
claimName: jellyfin-transcode
- name: media
persistentVolumeClaim:
claimName: jellyfin-media
volumeClaimTemplates:
# Per-pod scratch cache — RWO, disposable, one PVC per replica.
- metadata:
name: cache
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
storageClassName: cephrbd-fast-delete
volumeMode: Filesystem
+117
View File
@@ -0,0 +1,117 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: vmselect
namespace: observability
labels:
app.kubernetes.io/name: vmselect
app.kubernetes.io/instance: victoria-metrics
traefik.io/instance: internal
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vmselect.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vmselect.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.4
spec:
gatewayClassName: traefik-internal
listeners:
- name: http
port: 80
protocol: HTTP
hostname: vmselect.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
- name: https
port: 443
protocol: HTTPS
hostname: vmselect.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: vmselect-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: vminsert
namespace: observability
labels:
app.kubernetes.io/name: vminsert
app.kubernetes.io/instance: victoria-metrics
traefik.io/instance: internal
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vminsert.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vminsert.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.4
spec:
gatewayClassName: traefik-internal
listeners:
- name: http
port: 80
protocol: HTTP
hostname: vminsert.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
- name: https
port: 443
protocol: HTTPS
hostname: vminsert.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: vminsert-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: vmagent
namespace: observability
labels:
app.kubernetes.io/name: vmagent
app.kubernetes.io/instance: victoria-metrics
traefik.io/instance: internal
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vmagent.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vmagent.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.4
spec:
gatewayClassName: traefik-internal
listeners:
- name: http
port: 80
protocol: HTTP
hostname: vmagent.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
- name: https
port: 443
protocol: HTTPS
hostname: vmagent.k8s.syd1.au.unkin.net
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: vmagent-tls
+165
View File
@@ -0,0 +1,165 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vmselect-http-redirect
namespace: observability
labels:
app.kubernetes.io/name: vmselect
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vmselect.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vmselect
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vmselect
namespace: observability
labels:
app.kubernetes.io/name: vmselect
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vmselect.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vmselect
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: vmselect-main
port: 8481
weight: 1
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vminsert-http-redirect
namespace: observability
labels:
app.kubernetes.io/name: vminsert
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vminsert.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vminsert
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vminsert
namespace: observability
labels:
app.kubernetes.io/name: vminsert
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vminsert.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vminsert
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: vminsert-main
port: 8480
weight: 1
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vmagent-http-redirect
namespace: observability
labels:
app.kubernetes.io/name: vmagent
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vmagent.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vmagent
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
matches:
- path:
type: PathPrefix
value: /
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vmagent
namespace: observability
labels:
app.kubernetes.io/name: vmagent
app.kubernetes.io/instance: victoria-metrics
spec:
hostnames:
- vmagent.k8s.syd1.au.unkin.net
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: vmagent
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: vmagent-main
port: 8429
weight: 1
matches:
- path:
type: PathPrefix
value: /
@@ -4,3 +4,7 @@ kind: Kustomization
resources:
- namespace.yaml
- vmcluster.yaml
- vmagent.yaml
- gateway.yaml
- httproute.yaml
+122
View File
@@ -0,0 +1,122 @@
---
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
name: main
namespace: observability
spec:
replicaCount: 2
scrapeInterval: 15s
# Also consume VMServiceScrape / VMPodScrape / VMNodeScrape from every namespace
# (the operator auto-converts Prometheus ServiceMonitors -> VMServiceScrape).
selectAllByDefault: true
extraArgs:
loggerFormat: json
remoteWrite:
- url: http://vminsert-main.observability.svc.cluster.local:8480/insert/0/prometheus/
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
# Reflected Vault intermediate CA (unkin.net) for verifying puppet Consul + metrics targets.
volumes:
- name: vault-ca
secret:
secretName: vault-ca-cert
volumeMounts:
- name: vault-ca
mountPath: /etc/vmagent-tls
readOnly: true
inlineScrapeConfig: |
- job_name: vmagent
static_configs:
- targets: ["localhost:8429"]
- job_name: "kubernetes-apiservers"
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
action: keep
regex: default;kubernetes;https
- job_name: "kubernetes-nodes"
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- job_name: "kubernetes-nodes-cadvisor"
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
metrics_path: /metrics/cadvisor
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- source_labels: [__metrics_path__]
target_label: metrics_path
metric_relabel_configs:
- action: replace
source_labels: [pod]
regex: '(.+)'
target_label: pod_name
replacement: '${1}'
- action: replace
source_labels: [container]
regex: '(.+)'
target_label: container_name
replacement: '${1}'
- action: replace
target_label: name
replacement: k8s_stub
- action: replace
source_labels: [id]
regex: '^/system\.slice/(.+)\.service$'
target_label: systemd_service_name
replacement: '${1}'
# puppet-prod Consul service discovery (same targets as the puppet vmagent).
# consul.service.consul resolves to the puppet Consul from in-cluster pods.
- job_name: consul
consul_sd_configs:
- server: consul.service.consul:443
scheme: https
tls_config:
ca_file: /etc/vmagent-tls/ca.crt
relabel_configs:
- source_labels: [__meta_consul_tagpresent_metrics]
regex: "true"
action: keep
- source_labels: [__meta_consul_node, __meta_consul_service_port]
separator: ":"
target_label: __address__
replacement: "${1}:${2}"
action: replace
- source_labels: [__meta_consul_tag_metrics_scheme]
target_label: __scheme__
action: replace
- target_label: __metrics_path__
replacement: /metrics
- source_labels: [__meta_consul_tag_metrics_job]
target_label: job
action: replace
tls_config:
ca_file: /etc/vmagent-tls/ca.crt
+115
View File
@@ -0,0 +1,115 @@
---
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMCluster
metadata:
name: main
namespace: observability
spec:
retentionPeriod: "180d"
replicationFactor: 2
vmstorage:
replicaCount: 2
extraArgs:
dedup.minScrapeInterval: 15s
loggerFormat: json
storage:
volumeClaimTemplate:
spec:
storageClassName: cephrbd-fast-delete
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "2"
memory: 8Gi
vmselect:
replicaCount: 2
extraArgs:
dedup.minScrapeInterval: 15s
loggerFormat: json
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 1024Mi
hpa:
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
selectPolicy: Max
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
selectPolicy: Min
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
vminsert:
replicaCount: 2
extraArgs:
loggerFormat: json
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 1024Mi
hpa:
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
selectPolicy: Max
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
selectPolicy: Min
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
@@ -0,0 +1,6 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../base/jellyfin
@@ -6,17 +6,3 @@ namespace: observability
resources:
- ../../../base/observability
helmCharts:
- name: victoria-metrics-cluster
repo: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/virtual/helm
version: "0.33.0"
releaseName: victoria-metrics-cluster
namespace: observability
valuesFile: values-vmcluster.yaml
- name: victoria-metrics-agent
repo: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/virtual/helm
version: "0.30.0"
releaseName: victoria-metrics-agent
namespace: observability
valuesFile: values-vmagent.yaml
@@ -1,102 +0,0 @@
image:
repository: victoriametrics/vmagent
pullPolicy: IfNotPresent
global:
scrape_interval: 15s
podDisruptionBudget:
enabled: true
maxUnavailable: 1
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8481"
replicaCount: 3
extraArgs:
envflag.enable: true
envflag.prefix: VM_
loggerFormat: json
httpListenAddr: :8429
service:
enabled: true
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vmagent.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vmagent.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.0
hosts:
- name: vmagent.k8s.syd1.au.unkin.net
path:
- /
port: http
tls:
- hosts:
- vmagent.k8s.syd1.au.unkin.net
secretName: vmagent-tls
ingressClassName: nginx
remoteWrite:
- url: http://victoria-metrics-cluster-vminsert.observability.svc.cluster.local:8480/insert/0/prometheus/
scrape_configs:
- job_name: vmagent
static_configs:
- targets: ["localhost:8429"]
- job_name: "kubernetes-apiservers"
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
action: keep
regex: default;kubernetes;https
- job_name: "kubernetes-nodes"
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- job_name: "kubernetes-nodes-cadvisor"
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
metrics_path: /metrics/cadvisor
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- source_labels: [__metrics_path__]
target_label: metrics_path
metric_relabel_configs:
- action: replace
source_labels: [pod]
regex: '(.+)'
target_label: pod_name
replacement: '${1}'
- action: replace
source_labels: [container]
regex: '(.+)'
target_label: container_name
replacement: '${1}'
- action: replace
target_label: name
replacement: k8s_stub
- action: replace
source_labels: [id]
regex: '^/system\.slice/(.+)\.service$'
target_label: systemd_service_name
replacement: '${1}'
@@ -1,185 +0,0 @@
vmselect:
enabled: true
image:
repository: victoriametrics/vmselect
pullPolicy: IfNotPresent
variant: cluster
extraArgs:
envflag.enable: true
envflag.prefix: VM_
loggerFormat: json
httpListenAddr: :8481
dedup.minScrapeInterval: 15s
replicationFactor: 2
resources:
limits:
cpu: 500m
memory: 1024Mi
requests:
cpu: 50m
memory: 128Mi
horizontalPodAutoscaler:
enabled: true
maxReplicas: 10
minReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
selectPolicy: Max
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
selectPolicy: Min
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8481"
podDisruptionBudget:
enabled: true
maxUnavailable: 1
replicaCount: 2
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vmselect.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vmselect.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.0
hosts:
- name: vmselect.k8s.syd1.au.unkin.net
path:
- /
port: http
tls:
- hosts:
- vmselect.k8s.syd1.au.unkin.net
secretName: vmselect-tls
ingressClassName: nginx
vminsert:
enabled: true
image:
repository: victoriametrics/vminsert
variant: cluster
pullPolicy: IfNotPresent
extraArgs:
envflag.enable: true
envflag.prefix: VM_
loggerFormat: json
httpListenAddr: :8480
replicationFactor: 2
resources:
limits:
cpu: 500m
memory: 1024Mi
requests:
cpu: 50m
memory: 128Mi
horizontalPodAutoscaler:
enabled: true
maxReplicas: 10
minReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleUp:
stabilizationWindowSeconds: 0
selectPolicy: Max
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
scaleDown:
stabilizationWindowSeconds: 300
selectPolicy: Min
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8480"
podDisruptionBudget:
enabled: true
maxUnavailable: 1
replicaCount: 2
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: vault-issuer
cert-manager.io/common-name: vminsert.k8s.syd1.au.unkin.net
cert-manager.io/private-key-size: "4096"
external-dns.alpha.kubernetes.io/hostname: vminsert.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.0
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
hosts:
- name: vminsert.k8s.syd1.au.unkin.net
path:
- /
port: http
tls:
- hosts:
- vminsert.k8s.syd1.au.unkin.net
secretName: vminsert-tls
ingressClassName: nginx
vmstorage:
enabled: true
image:
repository: victoriametrics/vmstorage
variant: cluster
pullPolicy: IfNotPresent
retentionPeriod: 180d
extraArgs:
envflag.enable: true
envflag.prefix: VM_
loggerFormat: json
httpListenAddr: :8482
dedup.minScrapeInterval: 15s
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8482"
podDisruptionBudget:
enabled: true
maxUnavailable: 1
persistentVolume:
enabled: true
name: vmstorage-volume
accessModes:
- ReadWriteOnce
storageClassName: cephrbd-fast-delete
mountPath: /storage
size: 200Gi
replicaCount: 3
podManagementPolicy: OrderedReady
@@ -4,6 +4,7 @@ kind: Kustomization
resources:
- aitooling.yaml
- media.yaml
- observability.yaml
- platform.yaml
- storage.yaml
+31
View File
@@ -0,0 +1,31 @@
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: media-apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://git.unkin.net/unkin/argocd-apps
revision: HEAD
directories:
- path: apps/overlays/*/jellyfin
template:
metadata:
name: 'media-{{path[3]}}'
spec:
project: media
source:
repoURL: https://git.unkin.net/unkin/argocd-apps
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path[3]}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- ServerSideApply=true
+1
View File
@@ -4,6 +4,7 @@ kind: Kustomization
resources:
- aitooling.yaml
- media.yaml
- observability.yaml
- platform.yaml
- storage.yaml
+19
View File
@@ -0,0 +1,19 @@
---
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: media
namespace: argocd
spec:
description: Media services
sourceRepos:
- https://git.unkin.net/unkin/argocd-apps
destinations:
- namespace: 'jellyfin'
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceWhitelist:
- group: '*'
kind: '*'
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,371 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"editable": {
"type": "boolean",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"folderRef": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"folderUID": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"interval": {
"format": "duration",
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"name": {
"type": "string"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"rules": {
"items": {
"properties": {
"annotations": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"condition": {
"type": "string"
},
"dashboardUid": {
"type": "string"
},
"data": {
"items": {
"properties": {
"datasourceUid": {
"type": "string"
},
"model": {
"x-kubernetes-preserve-unknown-fields": true
},
"queryType": {
"type": "string"
},
"refId": {
"type": "string"
},
"relativeTimeRange": {
"properties": {
"from": {
"format": "int64",
"type": "integer"
},
"to": {
"format": "int64",
"type": "integer"
}
},
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"execErrState": {
"enum": [
"OK",
"Alerting",
"Error",
"KeepLast"
],
"type": "string"
},
"for": {
"default": "0s",
"pattern": "^([0-9]+(\\.[0-9]+)?(s|m|h|d|w))+$",
"type": "string"
},
"isPaused": {
"type": "boolean"
},
"keepFiringFor": {
"format": "duration",
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"missingSeriesEvalsToResolve": {
"format": "int64",
"type": "integer"
},
"noDataState": {
"enum": [
"Alerting",
"NoData",
"OK",
"KeepLast"
],
"type": "string"
},
"notificationSettings": {
"properties": {
"active_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"group_by": {
"items": {
"type": "string"
},
"type": "array"
},
"group_interval": {
"type": "string"
},
"group_wait": {
"type": "string"
},
"mute_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"receiver": {
"minLength": 1,
"type": "string"
},
"repeat_interval": {
"type": "string"
}
},
"required": [
"receiver"
],
"type": "object"
},
"panelId": {
"type": "integer"
},
"record": {
"properties": {
"from": {
"type": "string"
},
"metric": {
"type": "string"
},
"targetDatasourceUid": {
"type": "string"
}
},
"required": [
"from",
"metric"
],
"type": "object"
},
"title": {
"example": "Always firing",
"maxLength": 190,
"minLength": 1,
"type": "string"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string"
}
},
"required": [
"condition",
"data",
"execErrState",
"for",
"noDataState",
"title",
"uid"
],
"type": "object"
},
"minItems": 1,
"type": "array"
},
"suspend": {
"type": "boolean"
}
},
"required": [
"instanceSelector",
"interval",
"rules"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "Only one of FolderUID or FolderRef can be set and one must be defined",
"rule": "(has(self.folderUID) && !(has(self.folderRef))) || (has(self.folderRef) && !(has(self.folderUID)))"
},
{
"message": "spec.editable is immutable",
"rule": "((!has(oldSelf.editable) && !has(self.editable)) || (has(oldSelf.editable) && has(self.editable)))"
},
{
"message": "spec.folderUID is immutable",
"rule": "((!has(oldSelf.folderUID) && !has(self.folderUID)) || (has(oldSelf.folderUID) && has(self.folderUID)))"
},
{
"message": "spec.folderRef is immutable",
"rule": "((!has(oldSelf.folderRef) && !has(self.folderRef)) || (has(oldSelf.folderRef) && has(self.folderRef)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,348 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"disableResolveMessage": {
"type": "boolean"
},
"editable": {
"type": "boolean",
"x-kubernetes-validations": [
{
"message": "spec.editable is immutable",
"rule": "self == oldSelf"
}
]
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"name": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.name is immutable",
"rule": "self == oldSelf"
}
]
},
"receivers": {
"items": {
"properties": {
"disableResolveMessage": {
"type": "boolean"
},
"settings": {
"x-kubernetes-preserve-unknown-fields": true
},
"type": {
"minLength": 1,
"type": "string"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string"
},
"valuesFrom": {
"items": {
"properties": {
"targetPath": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object",
"x-kubernetes-validations": [
{
"message": "Either configMapKeyRef or secretKeyRef must be set",
"rule": "(has(self.configMapKeyRef) && !has(self.secretKeyRef)) || (!has(self.configMapKeyRef) && has(self.secretKeyRef))"
}
]
}
},
"required": [
"targetPath",
"valueFrom"
],
"type": "object"
},
"maxItems": 99,
"type": "array"
}
},
"required": [
"settings",
"type"
],
"type": "object"
},
"maxItems": 99,
"type": "array"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"settings": {
"x-kubernetes-preserve-unknown-fields": true
},
"suspend": {
"type": "boolean"
},
"type": {
"minLength": 1,
"type": "string"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "self == oldSelf"
}
]
},
"valuesFrom": {
"items": {
"properties": {
"targetPath": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object",
"x-kubernetes-validations": [
{
"message": "Either configMapKeyRef or secretKeyRef must be set",
"rule": "(has(self.configMapKeyRef) && !has(self.secretKeyRef)) || (!has(self.configMapKeyRef) && has(self.secretKeyRef))"
}
]
}
},
"required": [
"targetPath",
"valueFrom"
],
"type": "object"
},
"maxItems": 99,
"type": "array"
}
},
"required": [
"instanceSelector"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "spec.name is immutable",
"rule": "((!has(oldSelf.name) && !has(self.name)) || (has(oldSelf.name) && has(self.name)))"
},
{
"message": "spec.editable is immutable",
"rule": "((!has(oldSelf.editable) && !has(self.editable)) || (has(oldSelf.editable) && has(self.editable)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,492 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"configMapRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"contentCacheDuration": {
"type": "string"
},
"datasources": {
"items": {
"properties": {
"datasourceName": {
"type": "string"
},
"inputName": {
"type": "string"
}
},
"required": [
"datasourceName",
"inputName"
],
"type": "object"
},
"type": "array"
},
"envFrom": {
"items": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"type": "array"
},
"envs": {
"items": {
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"folder": {
"type": "string"
},
"folderRef": {
"type": "string"
},
"folderUID": {
"type": "string"
},
"grafanaCom": {
"properties": {
"id": {
"type": "integer"
},
"revision": {
"type": "integer"
}
},
"required": [
"id"
],
"type": "object"
},
"gzipJson": {
"format": "byte",
"type": "string"
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"json": {
"type": "string"
},
"jsonnet": {
"type": "string"
},
"jsonnetLib": {
"properties": {
"fileName": {
"type": "string"
},
"gzipJsonnetProject": {
"format": "byte",
"type": "string"
},
"jPath": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"fileName",
"gzipJsonnetProject"
],
"type": "object"
},
"oci": {
"properties": {
"insecurePlainHTTP": {
"type": "boolean"
},
"path": {
"maxLength": 512,
"minLength": 1,
"type": "string"
},
"pullSecretRef": {
"properties": {
"name": {
"default": "",
"type": "string"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"reference": {
"maxLength": 512,
"minLength": 3,
"pattern": "^[^:@]+(:[^:@/]+|@sha256:[a-fA-F0-9]{64})$",
"type": "string"
}
},
"required": [
"path",
"reference"
],
"type": "object"
},
"plugins": {
"items": {
"properties": {
"name": {
"minLength": 1,
"type": "string"
},
"version": {
"pattern": "^((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?|latest)$",
"type": "string"
}
},
"required": [
"name",
"version"
],
"type": "object"
},
"type": "array"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "self == oldSelf"
}
]
},
"url": {
"pattern": "^https?://.+$",
"type": "string"
},
"urlAuthorization": {
"properties": {
"basicAuth": {
"properties": {
"password": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"username": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
}
},
"type": "object"
}
},
"required": [
"instanceSelector"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "Only one of folderUID or folderRef can be declared at the same time",
"rule": "(has(self.folderUID) && !(has(self.folderRef))) || (has(self.folderRef) && !(has(self.folderUID))) || !(has(self.folderRef) && (has(self.folderUID)))"
},
{
"message": "folder field cannot be set when folderUID or folderRef is already declared",
"rule": "(has(self.folder) && !(has(self.folderRef) || has(self.folderUID))) || !(has(self.folder))"
},
{
"message": "spec.uid is immutable",
"rule": "((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"NoMatchingInstances": {
"type": "boolean"
},
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"contentCache": {
"format": "byte",
"type": "string"
},
"contentTimestamp": {
"format": "date-time",
"type": "string"
},
"contentUrl": {
"type": "string"
},
"hash": {
"type": "string"
},
"lastResync": {
"format": "date-time",
"type": "string"
},
"uid": {
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,306 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"datasource": {
"properties": {
"access": {
"type": "string"
},
"basicAuth": {
"type": "boolean"
},
"basicAuthUser": {
"type": "string"
},
"database": {
"type": "string"
},
"editable": {
"type": "boolean"
},
"isDefault": {
"type": "boolean"
},
"jsonData": {
"type": "object",
"x-kubernetes-preserve-unknown-fields": true
},
"name": {
"type": "string"
},
"orgId": {
"format": "int64",
"type": "integer"
},
"secureJsonData": {
"type": "object",
"x-kubernetes-preserve-unknown-fields": true
},
"type": {
"type": "string"
},
"uid": {
"type": "string"
},
"url": {
"type": "string"
},
"user": {
"type": "string"
}
},
"type": "object"
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"plugins": {
"items": {
"properties": {
"name": {
"minLength": 1,
"type": "string"
},
"version": {
"pattern": "^((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?|latest)$",
"type": "string"
}
},
"required": [
"name",
"version"
],
"type": "object"
},
"type": "array"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "self == oldSelf"
}
]
},
"valuesFrom": {
"items": {
"properties": {
"targetPath": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object",
"x-kubernetes-validations": [
{
"message": "Either configMapKeyRef or secretKeyRef must be set",
"rule": "(has(self.configMapKeyRef) && !has(self.secretKeyRef)) || (!has(self.configMapKeyRef) && has(self.secretKeyRef))"
}
]
}
},
"required": [
"targetPath",
"valueFrom"
],
"type": "object"
},
"maxItems": 99,
"type": "array"
}
},
"required": [
"datasource",
"instanceSelector"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"NoMatchingInstances": {
"type": "boolean"
},
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"hash": {
"type": "string"
},
"lastMessage": {
"type": "string"
},
"lastResync": {
"format": "date-time",
"type": "string"
},
"uid": {
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,180 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"parentFolderRef": {
"type": "string"
},
"parentFolderUID": {
"type": "string"
},
"permissions": {
"type": "string"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"title": {
"type": "string"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "self == oldSelf"
}
]
}
},
"required": [
"instanceSelector"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "Only one of parentFolderUID or parentFolderRef can be set",
"rule": "(has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID)))"
},
{
"message": "spec.uid is immutable",
"rule": "((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"NoMatchingInstances": {
"type": "boolean"
},
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"hash": {
"type": "string"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,482 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"configMapRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"contentCacheDuration": {
"type": "string"
},
"datasources": {
"items": {
"properties": {
"datasourceName": {
"type": "string"
},
"inputName": {
"type": "string"
}
},
"required": [
"datasourceName",
"inputName"
],
"type": "object"
},
"type": "array"
},
"envFrom": {
"items": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
},
"type": "array"
},
"envs": {
"items": {
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"folderRef": {
"type": "string"
},
"folderUID": {
"type": "string"
},
"grafanaCom": {
"properties": {
"id": {
"type": "integer"
},
"revision": {
"type": "integer"
}
},
"required": [
"id"
],
"type": "object"
},
"gzipJson": {
"format": "byte",
"type": "string"
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"json": {
"type": "string"
},
"jsonnet": {
"type": "string"
},
"jsonnetLib": {
"properties": {
"fileName": {
"type": "string"
},
"gzipJsonnetProject": {
"format": "byte",
"type": "string"
},
"jPath": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"fileName",
"gzipJsonnetProject"
],
"type": "object"
},
"oci": {
"properties": {
"insecurePlainHTTP": {
"type": "boolean"
},
"path": {
"maxLength": 512,
"minLength": 1,
"type": "string"
},
"pullSecretRef": {
"properties": {
"name": {
"default": "",
"type": "string"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"reference": {
"maxLength": 512,
"minLength": 3,
"pattern": "^[^:@]+(:[^:@/]+|@sha256:[a-fA-F0-9]{64})$",
"type": "string"
}
},
"required": [
"path",
"reference"
],
"type": "object"
},
"plugins": {
"items": {
"properties": {
"name": {
"minLength": 1,
"type": "string"
},
"version": {
"pattern": "^((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?|latest)$",
"type": "string"
}
},
"required": [
"name",
"version"
],
"type": "object"
},
"type": "array"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"uid": {
"maxLength": 40,
"pattern": "^[a-zA-Z0-9-_]+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.uid is immutable",
"rule": "self == oldSelf"
}
]
},
"url": {
"pattern": "^https?://.+$",
"type": "string"
},
"urlAuthorization": {
"properties": {
"basicAuth": {
"properties": {
"password": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"username": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
}
},
"type": "object"
}
},
"required": [
"instanceSelector"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "Only one of folderUID or folderRef can be declared at the same time",
"rule": "(has(self.folderUID) && !(has(self.folderRef))) || (has(self.folderRef) && !(has(self.folderUID))) || !(has(self.folderRef) && (has(self.folderUID)))"
},
{
"message": "spec.uid is immutable",
"rule": "((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"contentCache": {
"format": "byte",
"type": "string"
},
"contentTimestamp": {
"format": "date-time",
"type": "string"
},
"contentUrl": {
"type": "string"
},
"hash": {
"type": "string"
},
"lastResync": {
"format": "date-time",
"type": "string"
},
"uid": {
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,300 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"patch": {
"properties": {
"env": {
"items": {
"properties": {
"name": {
"type": "string"
},
"valueFrom": {
"properties": {
"configMapKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"grafanaRef": {
"properties": {
"apiVersion": {
"type": "string"
},
"fieldPath": {
"type": "string"
}
},
"required": [
"fieldPath"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"secretKeyRef": {
"properties": {
"key": {
"type": "string"
},
"name": {
"default": "",
"type": "string"
},
"optional": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object",
"x-kubernetes-map-type": "atomic"
}
},
"type": "object"
}
},
"required": [
"name",
"valueFrom"
],
"type": "object"
},
"type": "array"
},
"scripts": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"scripts"
],
"type": "object"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"template": {
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"metadata": {
"properties": {
"annotations": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"name": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"namespace": {
"type": "string",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
}
},
"required": [
"name"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "namespace is immutable",
"rule": "((!has(oldSelf.__namespace__) && !has(self.__namespace__)) || (has(oldSelf.__namespace__) && has(self.__namespace__)))"
}
]
},
"spec": {
"x-kubernetes-preserve-unknown-fields": true
}
},
"required": [
"apiVersion",
"kind",
"metadata"
],
"type": "object"
}
},
"required": [
"instanceSelector",
"template"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,212 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"editable": {
"default": true,
"type": "boolean",
"x-kubernetes-validations": [
{
"message": "spec.editable is immutable",
"rule": "self == oldSelf"
}
]
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"name": {
"type": "string"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"time_intervals": {
"items": {
"properties": {
"days_of_month": {
"items": {
"type": "string"
},
"type": "array"
},
"location": {
"type": "string"
},
"months": {
"items": {
"type": "string"
},
"type": "array"
},
"times": {
"items": {
"properties": {
"end_time": {
"type": "string"
},
"start_time": {
"type": "string"
}
},
"required": [
"end_time",
"start_time"
],
"type": "object"
},
"type": "array"
},
"weekdays": {
"items": {
"type": "string"
},
"type": "array"
},
"years": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"minItems": 1,
"type": "array"
}
},
"required": [
"instanceSelector",
"name",
"time_intervals"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,314 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"editable": {
"type": "boolean",
"x-kubernetes-validations": [
{
"message": "Value is immutable",
"rule": "self == oldSelf"
}
]
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"route": {
"properties": {
"active_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"continue": {
"type": "boolean"
},
"group_by": {
"items": {
"type": "string"
},
"type": "array"
},
"group_interval": {
"type": "string"
},
"group_wait": {
"type": "string"
},
"match_re": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"matchers": {
"items": {
"properties": {
"isEqual": {
"type": "boolean"
},
"isRegex": {
"type": "boolean"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"isRegex",
"value"
],
"type": "object"
},
"type": "array"
},
"mute_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"object_matchers": {
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"type": "array"
},
"provenance": {
"type": "string"
},
"receiver": {
"minLength": 1,
"type": "string"
},
"repeat_interval": {
"type": "string"
},
"routeSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"routes": {
"x-kubernetes-preserve-unknown-fields": true
}
},
"required": [
"receiver"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "continue is invalid on the top level route node",
"rule": "!has(self.__continue__)"
},
{
"message": "match_re is invalid on the top level route node",
"rule": "!has(self.match_re)"
},
{
"message": "matchers is invalid on the top level route node",
"rule": "!has(self.matchers)"
},
{
"message": "object_matchers is invalid on the top level route node",
"rule": "!has(self.object_matchers)"
},
{
"message": "mute_time_intervals is invalid on the top level route node",
"rule": "!has(self.mute_time_intervals)"
},
{
"message": "active_time_intervals is invalid on the top level route node",
"rule": "!has(self.active_time_intervals)"
}
]
},
"suspend": {
"type": "boolean"
}
},
"required": [
"instanceSelector",
"route"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "spec.editable is immutable",
"rule": "((!has(oldSelf.editable) && !has(self.editable)) || (has(oldSelf.editable) && has(self.editable)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"discoveredRoutes": {
"items": {
"type": "string"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,199 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"active_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"continue": {
"type": "boolean"
},
"group_by": {
"items": {
"type": "string"
},
"type": "array"
},
"group_interval": {
"type": "string"
},
"group_wait": {
"type": "string"
},
"match_re": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"matchers": {
"items": {
"properties": {
"isEqual": {
"type": "boolean"
},
"isRegex": {
"type": "boolean"
},
"name": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"isRegex",
"value"
],
"type": "object"
},
"type": "array"
},
"mute_time_intervals": {
"items": {
"type": "string"
},
"type": "array"
},
"object_matchers": {
"items": {
"items": {
"type": "string"
},
"type": "array"
},
"type": "array"
},
"provenance": {
"type": "string"
},
"receiver": {
"minLength": 1,
"type": "string"
},
"repeat_interval": {
"type": "string"
},
"routeSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"routes": {
"x-kubernetes-preserve-unknown-fields": true
}
},
"required": [
"receiver"
],
"type": "object"
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,163 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"allowCrossNamespaceImport": {
"default": false,
"type": "boolean"
},
"editable": {
"type": "boolean",
"x-kubernetes-validations": [
{
"message": "spec.editable is immutable",
"rule": "self == oldSelf"
}
]
},
"instanceSelector": {
"properties": {
"matchExpressions": {
"items": {
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"values": {
"items": {
"type": "string"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
}
},
"required": [
"key",
"operator"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-type": "atomic"
},
"matchLabels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
},
"type": "object",
"x-kubernetes-map-type": "atomic",
"x-kubernetes-validations": [
{
"message": "spec.instanceSelector is immutable",
"rule": "self == oldSelf"
}
]
},
"name": {
"type": "string"
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string"
},
"suspend": {
"type": "boolean"
},
"template": {
"type": "string"
}
},
"required": [
"instanceSelector",
"name"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "spec.editable is immutable",
"rule": "((!has(oldSelf.editable) && !has(self.editable)) || (has(oldSelf.editable) && has(self.editable)))"
},
{
"message": "disabling spec.allowCrossNamespaceImport requires a recreate to ensure desired state",
"rule": "!oldSelf.allowCrossNamespaceImport || (oldSelf.allowCrossNamespaceImport && self.allowCrossNamespaceImport)"
}
]
},
"status": {
"properties": {
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"required": [
"spec"
],
"type": "object"
}
@@ -0,0 +1,221 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"type": "object"
},
"spec": {
"properties": {
"instanceName": {
"minLength": 1,
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.instanceName is immutable",
"rule": "self == oldSelf"
}
]
},
"isDisabled": {
"default": false,
"type": "boolean"
},
"name": {
"minLength": 1,
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.name is immutable",
"rule": "self == oldSelf"
}
]
},
"resyncPeriod": {
"pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|\u00b5s|ms|s|m|h))+$",
"type": "string",
"x-kubernetes-validations": [
{
"message": "spec.resyncPeriod must be greater than 0",
"rule": "duration(self) > duration('0s')"
}
]
},
"role": {
"enum": [
"Viewer",
"Editor",
"Admin"
],
"type": "string"
},
"suspend": {
"default": false,
"type": "boolean"
},
"tokens": {
"items": {
"properties": {
"expires": {
"format": "date-time",
"type": "string"
},
"name": {
"minLength": 1,
"type": "string"
},
"secretName": {
"minLength": 1,
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array",
"x-kubernetes-list-map-keys": [
"name"
],
"x-kubernetes-list-type": "map"
}
},
"required": [
"instanceName",
"role"
],
"type": "object",
"x-kubernetes-validations": [
{
"message": "spec.name is immutable",
"rule": "((!has(oldSelf.name) && !has(self.name)) || (has(oldSelf.name) && has(self.name)))"
}
]
},
"status": {
"properties": {
"account": {
"properties": {
"id": {
"format": "int64",
"type": "integer"
},
"isDisabled": {
"type": "boolean"
},
"login": {
"type": "string"
},
"name": {
"type": "string"
},
"role": {
"type": "string"
},
"tokens": {
"items": {
"properties": {
"expires": {
"format": "date-time",
"type": "string"
},
"id": {
"format": "int64",
"type": "integer"
},
"name": {
"type": "string"
},
"secret": {
"properties": {
"name": {
"type": "string"
},
"namespace": {
"type": "string"
}
},
"type": "object"
}
},
"required": [
"id",
"name"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"id",
"isDisabled",
"login",
"name",
"role"
],
"type": "object"
},
"conditions": {
"items": {
"properties": {
"lastTransitionTime": {
"format": "date-time",
"type": "string"
},
"message": {
"maxLength": 32768,
"type": "string"
},
"observedGeneration": {
"format": "int64",
"minimum": 0,
"type": "integer"
},
"reason": {
"maxLength": 1024,
"minLength": 1,
"pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
"type": "string"
},
"status": {
"enum": [
"True",
"False",
"Unknown"
],
"type": "string"
},
"type": {
"maxLength": 316,
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
"type": "string"
}
},
"required": [
"lastTransitionTime",
"message",
"reason",
"status",
"type"
],
"type": "object"
},
"type": "array"
},
"lastResync": {
"format": "date-time",
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
}