Stage 5: installer chart + release infra, kind e2e pass through the chart
Release / test (push) Successful in 2m48s
CI / chart (push) Successful in 1s
CI / security (push) Successful in 1m3s
CI / test (push) Successful in 2m5s
Release / chart (push) Successful in 4s
Release / image (push) Successful in 7m6s
Release / scan-image (push) Failing after 33s
Release / test (push) Successful in 2m48s
CI / chart (push) Successful in 1s
CI / security (push) Successful in 1m3s
CI / test (push) Successful in 2m5s
Release / chart (push) Successful in 4s
Release / image (push) Successful in 7m6s
Release / scan-image (push) Failing after 33s
Chart (charts/terdut-operator) generated via kubebuilder's own helm/v2-alpha plugin from config/'s kustomize output -- CRDs + manager Deployment/RBAC come from the same markers every other stage already generates, one source of truth. Hand-added on top: the optional terdutServer values block (DESIGN.md §10's "helm install and get a server" path, off by default) and the release-skill plumbing -- .release.conf, release-vars/helm-lint/push/ helm-package/helm-push/release Makefile targets, .gitea/workflows/release.yaml (test -> image/chart -> scan-image) -- mirroring terdut-server's own shape (registry/namespace convention, multi-arch buildx push, trivy/govulncheck/ gitleaks scans). ci.yaml gains security and chart jobs to match. Two real issues caught while wiring this, fixed before either shipped: - Dockerfile's builder stage didn't pin --platform=$BUILDPLATFORM, which would have made a multi-arch release build fail outright on this org's runners (no binfmt registration) -- same fix terdut-server's own Dockerfile already needed for the same reason. - govulncheck found one real, reachable finding: google.golang.org/grpc v1.82.1 (transitive via controller-runtime's otel exporter), fixed by bumping to v1.83.1. Full golden-path kind e2e pass, this time through `helm install` rather than raw kustomize: TerdutServer (real terdut-server v0.33.0 image) -> TerdutTeam -> one of each child kind, each confirmed Ready and then independently confirmed against terdut-server's own API from inside the cluster (not just the operator's own status). Deleted every CR in reverse order and confirmed server-side cleanup the same independent way for all three child kinds, the team, and the server. No new bugs found -- Stage 1's own kind pass already caught what a real cluster catches that envtest can't. Also dropped the kubebuilder helm plugin's default .github/workflows/ scaffold, same as Stage 0 already did for the main scaffold: this org runs on Gitea, not GitHub. Not done here, deliberately: an actual tagged release. release-preflight found no terdut-operator/ entry under Ryuvia/charts yet to bump -- that one-time wrapper bootstrap is a decision about deploying this operator for real, not a side effect of finishing this stage. make fmt lint test helm-lint build all clean.
This commit is contained in:
@@ -78,6 +78,54 @@ jobs:
|
||||
- name: Format, lint and test
|
||||
run: make fmt lint test
|
||||
|
||||
# No `chart` job yet -- there's no Helm chart until Stage 6 (ROADMAP.md). No
|
||||
# `security` job yet either (govulncheck/gitleaks, as terdut-server has); add one
|
||||
# alongside `test` once there's controller code worth scanning.
|
||||
# Runs on every push and pull request, unlike the image scan, which needs something
|
||||
# published to scan and so lives in release.yaml -- same split as terdut-server's.
|
||||
# govulncheck reads the source and its module graph, gitleaks reads the working
|
||||
# tree; neither sees what the other does.
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.26.6-bookworm
|
||||
volumes:
|
||||
- go-mod-cache:/go/pkg/mod
|
||||
- go-build-cache:/root/.cache/go-build
|
||||
- gobin-cache:/go/bin
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
if [ -n "$HEAD_SHA" ]; then
|
||||
git clone "$REPO_URL" .
|
||||
git checkout -q "$HEAD_SHA"
|
||||
else
|
||||
git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
fi
|
||||
|
||||
- name: Go vulnerability scan (govulncheck)
|
||||
run: make security-go
|
||||
|
||||
- name: Secret scan (gitleaks)
|
||||
run: make security-secrets
|
||||
|
||||
# Host mode, no `container:`: helm is baked into the runner image, and a container
|
||||
# job could not install it -- get.helm.sh is unreachable from the dind bridge, same
|
||||
# reason terdut-server's own chart job runs on the host.
|
||||
chart:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
if [ -n "$HEAD_SHA" ]; then
|
||||
git clone "$REPO_URL" .
|
||||
git checkout -q "$HEAD_SHA"
|
||||
else
|
||||
git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
fi
|
||||
|
||||
- name: Lint and render the chart
|
||||
run: make helm-lint
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
name: Release
|
||||
|
||||
# Checkout, interpolation and caching conventions match ci.yaml -- see the header there
|
||||
# for why there are no JS actions and why every `${{ }}` goes through `env:`.
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
# A tag is not normally re-pushed, so this mostly matters when one is force-moved during
|
||||
# a botched release -- the superseded run stops holding runner slots.
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REPO_URL: https://git.ryuvia.com/niklas/terdut-operator.git
|
||||
REGISTRY: git.ryuvia.com
|
||||
IMAGE: git.ryuvia.com/niklas/terdut-operator
|
||||
|
||||
jobs:
|
||||
# Gates every publishing job below. A tag that fails here publishes nothing: the
|
||||
# image and the chart are both downstream of it. No Postgres service, unlike
|
||||
# terdut-server's: this suite drives envtest (a fake API server), not a real database.
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.26.6-bookworm
|
||||
volumes:
|
||||
- go-mod-cache:/go/pkg/mod
|
||||
- go-build-cache:/root/.cache/go-build
|
||||
- gobin-cache:/go/bin
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
|
||||
- name: Format, lint and test
|
||||
run: make fmt lint test
|
||||
|
||||
# Host mode on purpose (no `container:`): this is the only context with a Docker CLI
|
||||
# pointed at the dind daemon. A `container:` job would sit on the dind bridge with no
|
||||
# docker socket at all -- same reason terdut-server's image job runs on the host.
|
||||
image:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
|
||||
- name: Log in to the registry
|
||||
env:
|
||||
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
run: echo "$TOKEN" | docker login "$REGISTRY" -u niklas --password-stdin
|
||||
|
||||
# buildx setup, the platform list and why there is no QEMU all live on the `push`
|
||||
# target now, so the same command publishes from a laptop and from here.
|
||||
- name: Build and push
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: make push VERSION="$REF_NAME"
|
||||
|
||||
# Also host mode: helm is baked into the runner image, and a `container:` job could
|
||||
# not install it -- get.helm.sh is unreachable from the dind bridge.
|
||||
chart:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
|
||||
# One publisher, triggered by the tag -- same reasoning as terdut-server's own
|
||||
# chart job: a workflow triggered by the main push cannot know the version it is
|
||||
# about to be tagged with, so there is no second publisher racing this one.
|
||||
- name: Refuse a non-version tag
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -eu
|
||||
if ! echo "$REF_NAME" | grep -qE '^v[0-9]'; then
|
||||
echo "::error::refusing to publish a chart for non-version tag ${REF_NAME}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Render before publishing, so a template that does not compile is found here,
|
||||
# not by Flux after the chart is already in the registry.
|
||||
- name: Lint and render the chart
|
||||
run: make helm-lint
|
||||
|
||||
- name: Package and push
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
echo "$TOKEN" | helm registry login "$REGISTRY" -u niklas --password-stdin
|
||||
make helm-package helm-push VERSION="$REF_NAME"
|
||||
|
||||
# Host mode, like image and chart: this needs a docker daemon to run trivy in, and a
|
||||
# `container:` job would sit on the dind bridge with none.
|
||||
#
|
||||
# Scans the pushed image, not a local one -- trivy cannot read a locally built image
|
||||
# on this runner (no docker socket in a container job, no shared filesystem with the
|
||||
# dind sidecar), so it pulls from the registry. Runs after `image` rather than gating
|
||||
# it: a red scan does not unpublish anything -- it means do not bump the wrapper
|
||||
# chart in Ryuvia/charts to this version. This pipeline does not deploy.
|
||||
scan-image:
|
||||
needs: image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
|
||||
|
||||
- name: Scan the pushed image (trivy)
|
||||
env:
|
||||
TRIVY_USERNAME: niklas
|
||||
TRIVY_PASSWORD: ${{ secrets.REGISTRY_TOKEN }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: make security-image VERSION="$REF_NAME"
|
||||
@@ -13,3 +13,7 @@ bin/
|
||||
# local kubeconfig/secrets some workflows write here
|
||||
*.kubeconfig
|
||||
cover.out
|
||||
|
||||
# scratch output: build-installer's consolidated manifest and packaged charts
|
||||
# (release-vars' HELM_CHART is charts/terdut-operator, committed; this is not)
|
||||
/dist/
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Read by the `release` skill (~/.claude/skills/release).
|
||||
#
|
||||
# Only what the Makefile cannot already say. IMAGE, HELM_CHART and HELM_REPO come from
|
||||
# `make release-vars`, so they have one definition and cannot drift from what is built.
|
||||
#
|
||||
# Defaults, set here only where this repo differs:
|
||||
# CHARTS_REPO=$HOME/git/charts CHARTS_DIR=<image basename>
|
||||
# GITEA_LOGIN=Ryuvia APPVERSION_PREFIX=
|
||||
# PROSE_LANG=en
|
||||
|
||||
# Same as the image basename, so this is only stated to be read rather than derived.
|
||||
CHARTS_DIR=terdut-operator
|
||||
|
||||
# This repo writes appVersion: "v0.1.0" (see charts/terdut-operator/Chart.yaml),
|
||||
# matching terdut-server's own v-prefixed style -- nothing reads the field, but people
|
||||
# do, and it should say the same thing the release tag does.
|
||||
APPVERSION_PREFIX=v
|
||||
|
||||
# English, for the same reason as terdut-server: this is an on-call tool's operator,
|
||||
# and nothing about its labels, API or docs is coupled to Swedish.
|
||||
PROSE_LANG=en
|
||||
@@ -7,19 +7,40 @@ short pitch.
|
||||
|
||||
## Checks
|
||||
|
||||
`make fmt lint test` is the CI gate (`.gitea/workflows/ci.yaml` calls these targets
|
||||
rather than restating them, same convention as terdut-server). `test` chains through
|
||||
the Kubebuilder-scaffolded `manifests`/`generate` (`controller-gen`) and `setup-envtest`
|
||||
targets automatically — everything needed lands in `bin/` (gitignored) on first run, no
|
||||
separate tool install required beyond Go itself and network access to
|
||||
`proxy.golang.org`/`storage.googleapis.com`.
|
||||
`make fmt lint test helm-lint` is the CI gate (`.gitea/workflows/ci.yaml`'s `test`,
|
||||
`security` and `chart` jobs call these targets rather than restating them, same
|
||||
convention as terdut-server). `test` chains through the Kubebuilder-scaffolded
|
||||
`manifests`/`generate` (`controller-gen`) and `setup-envtest` targets automatically —
|
||||
everything needed lands in `bin/` (gitignored) on first run, no separate tool install
|
||||
required beyond Go itself and network access to `proxy.golang.org`/`storage.googleapis.com`.
|
||||
`security` runs `make security-go`/`security-secrets` (govulncheck/gitleaks), same as
|
||||
terdut-server's own `security` job.
|
||||
|
||||
`make test-e2e` stands up a real `kind` cluster (`kind`/`docker` must be installed) and
|
||||
is not part of the CI gate yet — it has no service-image to test against until later
|
||||
ROADMAP stages produce one.
|
||||
The kubebuilder-scaffolded `make test-e2e` (a disposable, generic smoke test) is separate
|
||||
from the real golden-path `kind` e2e pass ROADMAP.md's Stage 5 describes (create every CRD
|
||||
kind, verify against terdut-server's own API, delete, verify gone) — the latter is a
|
||||
manual pass run and recorded in ROADMAP.md, not a CI job, matching Stage 1-4's own
|
||||
precedent of validating against a real cluster outside CI.
|
||||
|
||||
## Release
|
||||
|
||||
Not wired yet. `.release.conf` and the release-vars Makefile target land in ROADMAP.md's
|
||||
Stage 6, once there's an actual Helm chart to release — see that file before assuming
|
||||
the `release` skill's terdut-server/terdut-tui conventions already apply here.
|
||||
Wired as of Stage 5 (ROADMAP.md): `.release.conf`, `make release-vars`/`helm-lint`/
|
||||
`push`/`helm-package`/`helm-push`/`release`, and `.gitea/workflows/release.yaml`
|
||||
(`test` → `image`/`chart` → `scan-image`) all follow terdut-server's established shape —
|
||||
see that repo's Makefile/`.release.conf` for the shared reasoning, not restated here.
|
||||
|
||||
The chart is `charts/terdut-operator` (via kubebuilder's own `helm/v2-alpha` plugin,
|
||||
regenerate with `kubebuilder edit --plugins helm.kubebuilder.io/v2-alpha --output-dir
|
||||
charts --force` after `config/` changes, then re-review — `--force` does not touch
|
||||
`Chart.yaml` but does touch `values.yaml`, which carries hand-written additions, most
|
||||
importantly the optional `terdutServer` block, DESIGN.md §10). It installs the operator +
|
||||
CRDs + RBAC, and optionally one `TerdutServer` CR (`terdutServer.enabled`, off by default).
|
||||
|
||||
**One manual step the release skill's own automation does not cover**: `release-preflight`
|
||||
expects an existing `terdut-operator/` entry under `Ryuvia/charts` to bump on release
|
||||
(steps 8-10 of the skill). There is no such entry yet — this repo's first-ever release
|
||||
can publish its own image and chart (the `test`/`image`/`chart`/`scan-image` jobs), but
|
||||
the wrapper-chart bump and PR will fail until someone creates that initial wrapper entry
|
||||
in `Ryuvia/charts` by hand, the same one-time step every other onboarded repo already had
|
||||
done for it before its own first release. That's a deliberate decision to deploy this
|
||||
operator for real, not something to do as a side effect of finishing this stage.
|
||||
|
||||
+6
-1
@@ -1,7 +1,12 @@
|
||||
# Build the manager binary
|
||||
# Override BASE_IMAGE to build from another registry, e.g. docker.io/library/golang:1.26
|
||||
ARG BASE_IMAGE=golang:1.26
|
||||
FROM ${BASE_IMAGE} AS builder
|
||||
# --platform=$BUILDPLATFORM pins the builder to the machine doing the building, so a
|
||||
# multi-arch build compiles both targets natively instead of running an emulated arm64
|
||||
# toolchain under QEMU -- same reasoning, and the same fix, as terdut-server's own
|
||||
# Dockerfile: the CI runner has no binfmt registration and no way to get one, so
|
||||
# this is not just an optimization, it is what makes the arm64 image buildable at all.
|
||||
FROM --platform=$BUILDPLATFORM ${BASE_IMAGE} AS builder
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
|
||||
@@ -259,3 +259,190 @@ endef
|
||||
define gomodver
|
||||
$(shell go list -m -f '{{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}' $(1) 2>/dev/null)
|
||||
endef
|
||||
|
||||
##@ Helm Deployment
|
||||
|
||||
## Helm binary to use for deploying the chart
|
||||
HELM ?= helm
|
||||
## Namespace to deploy the Helm release
|
||||
HELM_NAMESPACE ?= terdut-operator-system
|
||||
## Name of the Helm release
|
||||
HELM_RELEASE ?= terdut-operator
|
||||
## Path to the Helm chart directory. Must stay equal to HELM_CHART below
|
||||
## (the release process's own name for this same path) -- two variables
|
||||
## because this one is kubebuilder's own scaffold and that one is the
|
||||
## release skill's contract, not because the path differs.
|
||||
HELM_CHART_DIR ?= charts/terdut-operator
|
||||
## Additional arguments to pass to helm commands
|
||||
HELM_EXTRA_ARGS ?=
|
||||
|
||||
.PHONY: install-helm
|
||||
install-helm: ## Install the latest version of Helm.
|
||||
@command -v $(HELM) >/dev/null 2>&1 || { \
|
||||
echo "Installing Helm..." && \
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash; \
|
||||
}
|
||||
|
||||
.PHONY: helm-deploy
|
||||
helm-deploy: install-helm ## Deploy manager to the K8s cluster via Helm. Specify an image with IMG.
|
||||
IMG="$(IMG)"; $(HELM) upgrade --install $(HELM_RELEASE) $(HELM_CHART_DIR) \
|
||||
--namespace $(HELM_NAMESPACE) \
|
||||
--create-namespace \
|
||||
--set manager.image.repository=$${IMG%:*} \
|
||||
--set manager.image.tag=$${IMG##*:} \
|
||||
--wait \
|
||||
--timeout 5m \
|
||||
$(HELM_EXTRA_ARGS)
|
||||
|
||||
.PHONY: helm-uninstall
|
||||
helm-uninstall: ## Uninstall the Helm release from the K8s cluster.
|
||||
$(HELM) uninstall $(HELM_RELEASE) --namespace $(HELM_NAMESPACE)
|
||||
|
||||
.PHONY: helm-status
|
||||
helm-status: ## Show Helm release status.
|
||||
$(HELM) status $(HELM_RELEASE) --namespace $(HELM_NAMESPACE)
|
||||
|
||||
.PHONY: helm-history
|
||||
helm-history: ## Show Helm release history.
|
||||
$(HELM) history $(HELM_RELEASE) --namespace $(HELM_NAMESPACE)
|
||||
|
||||
.PHONY: helm-rollback
|
||||
helm-rollback: ## Rollback to previous Helm release.
|
||||
$(HELM) rollback $(HELM_RELEASE) --namespace $(HELM_NAMESPACE)
|
||||
|
||||
##@ Release
|
||||
|
||||
# Everything below is read by the `release` skill (~/.claude/skills/release), not by
|
||||
# anything above it in this file -- mirrors terdut-server's Makefile section for
|
||||
# section, adapted for this repo (no Postgres service for tests, no CLI binaries to
|
||||
# cross-compile, one image + one chart to publish).
|
||||
|
||||
REGISTRY := git.ryuvia.com
|
||||
# The personal namespace, not ryuvia -- same reasoning as terdut-server: Gitea scopes
|
||||
# package visibility to the owner with no per-package override, so publishing here
|
||||
# keeps the image and chart anonymously pullable and Flux needs no registry
|
||||
# credentials to pull them.
|
||||
OWNER := niklas
|
||||
|
||||
IMAGE := $(REGISTRY)/$(OWNER)/terdut-operator
|
||||
HELM_CHART := charts/terdut-operator
|
||||
HELM_REPO := oci://$(REGISTRY)/$(OWNER)
|
||||
|
||||
.PHONY: release-vars
|
||||
release-vars: ## Print the variables the release process reads
|
||||
@printf 'IMAGE=%s\nHELM_CHART=%s\nHELM_REPO=%s\n' '$(IMAGE)' '$(HELM_CHART)' '$(HELM_REPO)'
|
||||
|
||||
# database is required (dsn xor postgresClusterRef, DatabaseSpec's own CEL rule) once
|
||||
# terdutServer.enabled, so the chart's own `required` calls fail a bare
|
||||
# `--set terdutServer.enabled=true` the same way a real install without a database
|
||||
# would be rejected at apply time -- this set gives that path something valid to
|
||||
# render against, the way terdut-server's own HELM_LINT_SET supplies its one
|
||||
# required field (database.dsn) for the same reason.
|
||||
HELM_LINT_SET = --set terdutServer.enabled=true \
|
||||
--set terdutServer.image.tag=v0.0.0 \
|
||||
--set terdutServer.networking.hostname=terdut.example.invalid \
|
||||
--set 'terdutServer.database.dsn=postgres://terdut@terdut-postgres:5432/terdut?sslmode=require'
|
||||
|
||||
.PHONY: helm-lint
|
||||
helm-lint: ## Lint and render the chart
|
||||
helm lint $(HELM_CHART)
|
||||
helm template terdut-operator $(HELM_CHART) --namespace terdut-operator-system >/dev/null
|
||||
# Second pass: the optional TerdutServer CR template (off by default, so the
|
||||
# bare render above never exercises it at all).
|
||||
helm lint $(HELM_CHART) $(HELM_LINT_SET)
|
||||
helm template terdut-operator $(HELM_CHART) --namespace terdut-operator-system \
|
||||
$(HELM_LINT_SET) >/dev/null
|
||||
|
||||
## --- publishing ---
|
||||
#
|
||||
# Exist so .gitea/workflows/release.yaml can call `make push` / `make helm-package
|
||||
# helm-push` instead of restating the build in YAML -- one definition, runnable
|
||||
# locally, reviewable in a diff. Publishing happens by pushing a tag; nothing else.
|
||||
#
|
||||
# VERSION is the git tag, passed in by the workflow. require-version is why a stray
|
||||
# local `make push` cannot publish: dev is not a version anyone releases.
|
||||
|
||||
VERSION ?= dev
|
||||
|
||||
# Helm requires strict SemVer -- strip a leading 'v' if present.
|
||||
CHART_VERSION := $(shell echo "$(VERSION)" | sed 's/^v//')
|
||||
|
||||
# Named RELEASE_PLATFORMS, not PLATFORMS: that name is already taken above by
|
||||
# kubebuilder's own docker-buildx target (a 4-platform list this repo's own release
|
||||
# process doesn't use), and `?=` on an already-set variable is a silent no-op, not an
|
||||
# override -- reusing it here would have quietly built s390x/ppc64le instead of the
|
||||
# two platforms this target actually intends.
|
||||
RELEASE_PLATFORMS ?= linux/amd64,linux/arm64
|
||||
BUILDX_BUILDER ?= terdut-operator-release
|
||||
|
||||
# An isolated repo list, same reasoning as terdut-server's: the machine-wide one is
|
||||
# not this build's business, and one unreachable entry in it aborts otherwise-fine
|
||||
# helm commands. HELM_REPOSITORY_CACHE is deliberately NOT overridden alongside it --
|
||||
# helm writes a refreshed index to the default cache and then looks for it there.
|
||||
HELM_ISOLATED = HELM_REPOSITORY_CONFIG=$(CURDIR)/.helm-repos.yaml
|
||||
|
||||
.PHONY: require-version
|
||||
require-version:
|
||||
@test "$(VERSION)" != "dev" || \
|
||||
(echo "VERSION=dev names no release -- pass VERSION=vX.Y.Z (the workflow passes the tag)" && exit 1)
|
||||
|
||||
# Multi-arch, so this is build-and-push in one step, same reasoning as
|
||||
# terdut-server's own `push`: buildx cannot load a multi-platform result into the
|
||||
# local image store, so there is no separate local-only `build` target here either.
|
||||
#
|
||||
# No QEMU: the Dockerfile's builder stage runs on $$BUILDPLATFORM and cross-compiles
|
||||
# via GOOS/GOARCH, so both platforms build natively -- same fix as terdut-server's
|
||||
# Dockerfile, for the same reason (this CI runner has no binfmt registration).
|
||||
.PHONY: push
|
||||
push: require-version ## Build and publish the multi-arch image
|
||||
docker buildx create --name $(BUILDX_BUILDER) --use 2>/dev/null || docker buildx use $(BUILDX_BUILDER)
|
||||
docker buildx build \
|
||||
--platform $(RELEASE_PLATFORMS) \
|
||||
--tag "$(IMAGE):latest" \
|
||||
--tag "$(IMAGE):$(VERSION)" \
|
||||
--push .
|
||||
|
||||
# --version/--app-version come from the tag, so Chart.yaml's own fields decide
|
||||
# nothing about what gets published -- same as terdut-server's chart.
|
||||
.PHONY: helm-package
|
||||
helm-package: require-version ## Package the chart, versioned from the tag
|
||||
$(HELM_ISOLATED) helm package $(HELM_CHART) \
|
||||
--version $(CHART_VERSION) \
|
||||
--app-version $(VERSION) \
|
||||
--destination dist
|
||||
|
||||
.PHONY: helm-push
|
||||
helm-push: require-version ## Push the packaged chart to the OCI registry
|
||||
$(HELM_ISOLATED) helm push dist/terdut-operator-$(CHART_VERSION).tgz $(HELM_REPO)
|
||||
|
||||
.PHONY: release
|
||||
release: push helm-package helm-push ## Publish image + chart (the workflow's one call)
|
||||
|
||||
## --- security ---
|
||||
|
||||
GOVULNCHECK_VERSION := v1.1.4
|
||||
GITLEAKS_VERSION := v8.30.0
|
||||
TRIVY_VERSION := 0.73.0
|
||||
|
||||
# Symbol-level, not dependency-level, same as terdut-server: govulncheck reports a
|
||||
# vulnerability only when the code can actually reach it.
|
||||
.PHONY: security-go
|
||||
security-go: ## Scan Go deps for known CVEs (govulncheck)
|
||||
go run golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION) ./...
|
||||
|
||||
# --no-git scans the working tree rather than the history, so this catches a secret
|
||||
# on the way in; it says nothing about what is already committed.
|
||||
.PHONY: security-secrets
|
||||
security-secrets: ## Scan the working tree for committed secrets (gitleaks)
|
||||
go run github.com/zricethezav/gitleaks/v8@$(GITLEAKS_VERSION) detect --no-git \
|
||||
--source . --redact --no-banner --exit-code 1
|
||||
|
||||
# Scans the pushed image, not a local one -- trivy cannot read a locally built image
|
||||
# on this runner, same reasoning as terdut-server. A red scan means: do not bump the
|
||||
# wrapper chart in Ryuvia/charts to this version; it does not unpublish anything.
|
||||
.PHONY: security-image
|
||||
security-image: require-version ## Scan the pushed image for CVEs (needs VERSION)
|
||||
docker run --rm -e TRIVY_USERNAME -e TRIVY_PASSWORD \
|
||||
-v trivy-cache:/root/.cache/trivy \
|
||||
docker.io/aquasec/trivy:$(TRIVY_VERSION) image --severity HIGH,CRITICAL \
|
||||
--ignore-unfixed --exit-code 1 $(IMAGE):$(VERSION)
|
||||
|
||||
@@ -6,6 +6,10 @@ cliVersion: 4.16.0
|
||||
domain: ryuvia.com
|
||||
layout:
|
||||
- go.kubebuilder.io/v4
|
||||
plugins:
|
||||
helm.kubebuilder.io/v2-alpha:
|
||||
manifests: dist/install.yaml
|
||||
output: charts
|
||||
projectName: terdut-operator
|
||||
repo: git.ryuvia.com/niklas/terdut-operator
|
||||
resources:
|
||||
|
||||
+47
@@ -181,6 +181,53 @@ New commits build forward over the old ones; no git history rewrite.
|
||||
→ one of each child kind → verify via terdut-server's own API that each
|
||||
object exists with the right shape → delete the CR → verify the
|
||||
server-side object is gone.
|
||||
- Chart built via kubebuilder's own `helm/v2-alpha` plugin from `config/`'s
|
||||
kustomize output (`charts/terdut-operator`), not hand-rolled -- CRDs +
|
||||
manager Deployment/RBAC come from the same markers/manifests every other
|
||||
stage already generates, so there's exactly one source of truth for
|
||||
them. Hand-added on top: the optional `terdutServer` values block (§10's
|
||||
"helm install and get a server" path), `.release.conf`, and the
|
||||
`release-vars`/`helm-lint`/`push`/`helm-package`/`helm-push`/`release`
|
||||
Makefile targets `.gitea/workflows/release.yaml` calls, mirroring
|
||||
terdut-server's own shape end to end (same registry/namespace
|
||||
convention, same multi-arch buildx push, same trivy/govulncheck/gitleaks
|
||||
scans). Also fixed while wiring this: the Dockerfile's builder stage
|
||||
didn't pin `--platform=$BUILDPLATFORM`, which would have made a
|
||||
multi-arch release build fail outright on this org's runners (no binfmt
|
||||
registration) -- caught before it ever shipped, not discovered mid-release;
|
||||
and govulncheck surfaced one real, reachable finding (`google.golang.org/grpc`
|
||||
v1.82.1, transitive via controller-runtime's otel exporter), fixed by
|
||||
bumping to v1.83.1.
|
||||
- **Done, 2026-10-01**: the full golden-path pass above, run for real
|
||||
against a `kind` cluster, installed via `helm install` (not raw
|
||||
kustomize/kubectl apply -- the first time the chart itself, not just
|
||||
`config/`, was exercised): `TerdutServer` (real terdut-server `v0.33.0`
|
||||
image, bring-your-own DSN against a throwaway in-cluster Postgres) →
|
||||
`TerdutTeam` → one `TerdutEscalationRule` + `TerdutDeadmanSwitch` +
|
||||
`TerdutAlertSource`, each confirmed `Ready` and then confirmed a second
|
||||
way, independent of the operator's own status: a `curl` pod inside the
|
||||
cluster, authenticated with the generated team credential, hit
|
||||
terdut-server's real API directly (`GET /api/teams/{id}/escalation`,
|
||||
`.../deadman/switches`, `.../integrations`) and got back exactly the
|
||||
policy/switch/integration each spec declared. Deleting every CR in
|
||||
reverse order was verified the same way: the escalation policy came back
|
||||
empty (its only available "undo"), the switch and the integration were
|
||||
both gone from their list endpoints, the team no longer resolved by
|
||||
name, and the Deployment/Service/every generated Secret were gone from
|
||||
the cluster. No new bugs found this pass -- Stage 1's own kind e2e pass
|
||||
already caught the two issues (`events.k8s.io` RBAC, the podman
|
||||
`.dockerignore` fix) a real cluster catches and `envtest` can't, and
|
||||
nothing since has touched that surface.
|
||||
- Not done in this pass, deliberately: an actual tagged release. `make
|
||||
release-vars`/`helm-lint`/`push`/`helm-package`/`helm-push` all work
|
||||
locally and `.gitea/workflows/release.yaml` is wired, but
|
||||
`release-preflight` found there is no `terdut-operator/` entry under
|
||||
`Ryuvia/charts` yet to bump -- every other onboarded repo had that
|
||||
one-time wrapper-chart bootstrap done for it before its own first
|
||||
release, and this one doesn't, since deploying this operator for real is
|
||||
a decision for whoever runs the cluster, not a side effect of finishing
|
||||
this stage. Cutting the first real release (and creating that wrapper
|
||||
entry) is therefore the next action, not yet taken.
|
||||
|
||||
## Deferred (§13, unchanged by this roadmap)
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Patterns to ignore when building Helm packages.
|
||||
# Operating system files
|
||||
.DS_Store
|
||||
|
||||
# Version control directories
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
|
||||
# Backup and temporary files
|
||||
*.swp
|
||||
*.tmp
|
||||
*.bak
|
||||
*.orig
|
||||
*~
|
||||
|
||||
# IDE and editor-related files
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Helm chart artifacts
|
||||
dist/chart/*.tgz
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: v2
|
||||
name: terdut-operator
|
||||
description: Installs terdut-operator (CRDs + controller) for terdut-server, and optionally one TerdutServer CR
|
||||
type: application
|
||||
|
||||
# These fields decide nothing: `make helm-package` passes --version and
|
||||
# --app-version from the release tag (same reasoning as terdut-server's own
|
||||
# chart). They're for whoever reads the tree before a tag exists.
|
||||
version: 0.1.0
|
||||
appVersion: "v0.1.0"
|
||||
|
||||
keywords:
|
||||
- kubernetes
|
||||
- operator
|
||||
- terdut
|
||||
|
||||
home: https://git.ryuvia.com/niklas/terdut-operator
|
||||
|
||||
annotations:
|
||||
kubebuilder.io/generated-by: kubebuilder
|
||||
@@ -0,0 +1,15 @@
|
||||
Thank you for installing {{ .Chart.Name }}.
|
||||
|
||||
Your release is named {{ .Release.Name }}.
|
||||
|
||||
The controller and CRDs have been installed in namespace {{ .Release.Namespace }}.
|
||||
|
||||
To verify the installation:
|
||||
|
||||
kubectl get pods -n {{ .Release.Namespace }}
|
||||
kubectl get customresourcedefinitions
|
||||
|
||||
To learn more about the release, try:
|
||||
|
||||
$ helm status {{ .Release.Name }} -n {{ .Release.Namespace }}
|
||||
$ helm get all {{ .Release.Name }} -n {{ .Release.Namespace }}
|
||||
@@ -0,0 +1,63 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "terdut-operator.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "terdut-operator.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Namespace for generated references.
|
||||
Always uses the Helm release namespace.
|
||||
*/}}
|
||||
{{- define "terdut-operator.namespaceName" -}}
|
||||
{{- .Release.Namespace }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Resource name with proper truncation for Kubernetes 63-character limit.
|
||||
Takes a dict with:
|
||||
- .suffix: Resource name suffix (e.g., "metrics", "webhook")
|
||||
- .context: Template context (root context with .Values, .Release, etc.)
|
||||
Dynamically calculates safe truncation to ensure total name length <= 63 chars.
|
||||
*/}}
|
||||
{{- define "terdut-operator.resourceName" -}}
|
||||
{{- $fullname := include "terdut-operator.fullname" .context }}
|
||||
{{- $suffix := .suffix }}
|
||||
{{- $maxLen := sub 62 (len $suffix) | int }}
|
||||
{{- if gt (len $fullname) $maxLen }}
|
||||
{{- printf "%s-%s" (trunc $maxLen $fullname | trimSuffix "-") $suffix | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" $fullname $suffix | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
ServiceAccount name to use.
|
||||
When enabled, use the chart's ServiceAccount name.
|
||||
When disabled, serviceAccount.name must be set; use "default" to pick the namespace default ServiceAccount.
|
||||
*/}}
|
||||
{{- define "terdut-operator.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.enabled }}
|
||||
{{- include "terdut-operator.resourceName" (dict "suffix" "controller-manager" "context" .) }}
|
||||
{{- else }}
|
||||
{{- required "serviceAccount.name is required when serviceAccount.enabled=false (set name: default explicitly to use the namespace default ServiceAccount)" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,198 @@
|
||||
{{- if .Values.crd.enabled }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
{{- if .Values.crd.keep }}
|
||||
"helm.sh/resource-policy": keep
|
||||
{{- end }}
|
||||
controller-gen.kubebuilder.io/version: v0.22.0
|
||||
name: terdutalertsources.terdut.ryuvia.com
|
||||
spec:
|
||||
group: terdut.ryuvia.com
|
||||
names:
|
||||
kind: TerdutAlertSource
|
||||
listKind: TerdutAlertSourceList
|
||||
plural: terdutalertsources
|
||||
singular: terdutalertsource
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.teamRef.name
|
||||
name: Team
|
||||
type: string
|
||||
- jsonPath: .status.integrationID
|
||||
name: IntegrationID
|
||||
type: integer
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].reason
|
||||
name: Reason
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: TerdutAlertSource is the Schema for the terdutalertsources API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: spec defines the desired state of TerdutAlertSource
|
||||
properties:
|
||||
kind:
|
||||
default: alertmanager
|
||||
description: |-
|
||||
kind is the alert source type. Only "alertmanager" is supported
|
||||
today, mirroring terdut-server's own CHECK constraint on
|
||||
integrations.kind (internal/db/migrations/003_teams.sql) --
|
||||
confirmed against source, not assumed. Changing it after the
|
||||
integration already exists rotates the webhook key (DESIGN.md §5's
|
||||
reconciliation table): the old one is deleted and a fresh one
|
||||
created, which breaks whatever sends to the old URL until the new
|
||||
Secret is picked up.
|
||||
enum:
|
||||
- alertmanager
|
||||
type: string
|
||||
name:
|
||||
description: |-
|
||||
name is this source's own display name server-side -- distinct from
|
||||
this object's own metadata.name. POST
|
||||
/api/teams/{teamID}/integrations {"name": ...} at creation, and what
|
||||
PATCH renames thereafter; renaming never rotates the webhook key.
|
||||
minLength: 1
|
||||
type: string
|
||||
teamRef:
|
||||
description: |-
|
||||
TerdutTeamRef names the TerdutTeam this resource belongs to. Always
|
||||
same-namespace as the CR itself (DESIGN.md §1: only TerdutTeam.spec.serverRef
|
||||
crosses namespaces in v1) -- no namespace field, unlike TerdutServerRef.
|
||||
properties:
|
||||
name:
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- teamRef
|
||||
type: object
|
||||
status:
|
||||
description: status defines the observed state of TerdutAlertSource
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
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
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
integrationID:
|
||||
description: integrationID is the server-side id.
|
||||
format: int64
|
||||
type: integer
|
||||
lastAppliedKind:
|
||||
description: |-
|
||||
lastAppliedKind is the kind the currently-live integration was
|
||||
actually created with -- compared against spec.kind on every
|
||||
reconcile to detect the one spec change that requires
|
||||
delete-and-recreate (DESIGN.md §5), since terdut-server's own API has
|
||||
no way to read a live integration's kind back for comparison.
|
||||
type: string
|
||||
observedGeneration:
|
||||
format: int64
|
||||
type: integer
|
||||
webhookURLSecretRef:
|
||||
description: |-
|
||||
webhookURLSecretRef names the generated Secret holding "url" and
|
||||
"key" -- the integration's webhook address and credential, shown by
|
||||
terdut-server's API exactly once, at creation (DESIGN.md §4.5), and
|
||||
never re-readable afterward, including from this status. Lives in
|
||||
this CR's own namespace with a plain OwnerReference (§7) -- unlike
|
||||
TerdutServer/TerdutTeam's credential Secrets, this one never crosses
|
||||
namespaces, so no finalizer cleanup is needed for it specifically.
|
||||
properties:
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,184 @@
|
||||
{{- if .Values.crd.enabled }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
{{- if .Values.crd.keep }}
|
||||
"helm.sh/resource-policy": keep
|
||||
{{- end }}
|
||||
controller-gen.kubebuilder.io/version: v0.22.0
|
||||
name: terdutdeadmanswitches.terdut.ryuvia.com
|
||||
spec:
|
||||
group: terdut.ryuvia.com
|
||||
names:
|
||||
kind: TerdutDeadmanSwitch
|
||||
listKind: TerdutDeadmanSwitchList
|
||||
plural: terdutdeadmanswitches
|
||||
singular: terdutdeadmanswitch
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.teamRef.name
|
||||
name: Team
|
||||
type: string
|
||||
- jsonPath: .status.switchID
|
||||
name: SwitchID
|
||||
type: integer
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].reason
|
||||
name: Reason
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: TerdutDeadmanSwitch is the Schema for the terdutdeadmanswitches
|
||||
API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: spec defines the desired state of TerdutDeadmanSwitch
|
||||
properties:
|
||||
matcher:
|
||||
description: |-
|
||||
matcher names the alerts this switch watches, e.g.
|
||||
"alertname=Watchdog,cluster=prod". One matcher per switch -- add
|
||||
another TerdutDeadmanSwitch instead of separating with ";"
|
||||
(terdut-server's own restriction, mirrored here so a bad spec is
|
||||
rejected at apply time).
|
||||
minLength: 1
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: 'one matcher per switch: add another TerdutDeadmanSwitch
|
||||
instead of separating with ;'
|
||||
rule: '!self.contains('';'')'
|
||||
name:
|
||||
description: |-
|
||||
name is optional, same as the API: left empty, terdut-server derives
|
||||
it from matcher's own canonical form, and that's what the
|
||||
idempotent-create lookup matches against too.
|
||||
type: string
|
||||
severity:
|
||||
default: critical
|
||||
enum:
|
||||
- critical
|
||||
- error
|
||||
- warning
|
||||
- info
|
||||
type: string
|
||||
teamRef:
|
||||
description: |-
|
||||
TerdutTeamRef names the TerdutTeam this resource belongs to. Always
|
||||
same-namespace as the CR itself (DESIGN.md §1: only TerdutTeam.spec.serverRef
|
||||
crosses namespaces in v1) -- no namespace field, unlike TerdutServerRef.
|
||||
properties:
|
||||
name:
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
timeout:
|
||||
description: timeout is a Go duration string, e.g. "15m".
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- matcher
|
||||
- teamRef
|
||||
- timeout
|
||||
type: object
|
||||
status:
|
||||
description: status defines the observed state of TerdutDeadmanSwitch
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
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
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
observedGeneration:
|
||||
format: int64
|
||||
type: integer
|
||||
switchID:
|
||||
description: switchID is the server-side id.
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,195 @@
|
||||
{{- if .Values.crd.enabled }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
{{- if .Values.crd.keep }}
|
||||
"helm.sh/resource-policy": keep
|
||||
{{- end }}
|
||||
controller-gen.kubebuilder.io/version: v0.22.0
|
||||
name: terdutescalationrules.terdut.ryuvia.com
|
||||
spec:
|
||||
group: terdut.ryuvia.com
|
||||
names:
|
||||
kind: TerdutEscalationRule
|
||||
listKind: TerdutEscalationRuleList
|
||||
plural: terdutescalationrules
|
||||
singular: terdutescalationrule
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.teamRef.name
|
||||
name: Team
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].reason
|
||||
name: Reason
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: TerdutEscalationRule is the Schema for the terdutescalationrules
|
||||
API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: spec defines the desired state of TerdutEscalationRule
|
||||
properties:
|
||||
fallbackTopic:
|
||||
type: string
|
||||
levels:
|
||||
items:
|
||||
description: |-
|
||||
EscalationLevel is one rung of the ladder: how long to wait, and who to
|
||||
page if nobody's acknowledged by then.
|
||||
properties:
|
||||
targets:
|
||||
items:
|
||||
description: |-
|
||||
EscalationTarget is one page within a level. username is required iff
|
||||
kind is "user" (terdut-server's own validation, internal/api/escalation.go's
|
||||
handleSetEscalation -- mirrored here as a CEL rule so a bad spec is
|
||||
rejected at apply time, not discovered on the next failed PUT).
|
||||
properties:
|
||||
kind:
|
||||
description: EscalationTargetKind is who one rung of the
|
||||
ladder pages.
|
||||
enum:
|
||||
- oncall
|
||||
- user
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: username is required when kind is user
|
||||
rule: self.kind != 'user' || has(self.username)
|
||||
- message: username must not be set when kind is oncall
|
||||
rule: self.kind != 'oncall' || !has(self.username)
|
||||
minItems: 1
|
||||
type: array
|
||||
timeout:
|
||||
description: timeout is a Go duration string, e.g. "5m".
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- targets
|
||||
- timeout
|
||||
type: object
|
||||
minItems: 1
|
||||
type: array
|
||||
repeatCount:
|
||||
format: int64
|
||||
maximum: 10
|
||||
minimum: 0
|
||||
type: integer
|
||||
teamRef:
|
||||
description: |-
|
||||
TerdutTeamRef names the TerdutTeam this resource belongs to. Always
|
||||
same-namespace as the CR itself (DESIGN.md §1: only TerdutTeam.spec.serverRef
|
||||
crosses namespaces in v1) -- no namespace field, unlike TerdutServerRef.
|
||||
properties:
|
||||
name:
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- levels
|
||||
- teamRef
|
||||
type: object
|
||||
status:
|
||||
description: status defines the observed state of TerdutEscalationRule
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
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
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
observedGeneration:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,457 @@
|
||||
{{- if .Values.crd.enabled }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
{{- if .Values.crd.keep }}
|
||||
"helm.sh/resource-policy": keep
|
||||
{{- end }}
|
||||
controller-gen.kubebuilder.io/version: v0.22.0
|
||||
name: terdutservers.terdut.ryuvia.com
|
||||
spec:
|
||||
group: terdut.ryuvia.com
|
||||
names:
|
||||
kind: TerdutServer
|
||||
listKind: TerdutServerList
|
||||
plural: terdutservers
|
||||
singular: terdutserver
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.replicas
|
||||
name: Replicas
|
||||
type: integer
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].reason
|
||||
name: Reason
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: TerdutServer is the Schema for the terdutservers API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: spec defines the desired state of TerdutServer
|
||||
properties:
|
||||
allowedTeams:
|
||||
description: |-
|
||||
allowedTeams gates cross-namespace TerdutTeams (DESIGN.md §4.6).
|
||||
Unused until TerdutTeam exists (ROADMAP.md Stage 2); present now so
|
||||
this CRD's schema doesn't need a breaking change to grow it later.
|
||||
properties:
|
||||
namespaces:
|
||||
description: |-
|
||||
AllowedTeamsNamespaces gates which namespaces a TerdutTeam may resolve a
|
||||
cross-namespace serverRef into this TerdutServer from (DESIGN.md §4.6).
|
||||
Same-namespace TerdutTeams are always allowed, regardless of this field.
|
||||
Modeled on Gateway API's Gateway.spec.allowedListeners.namespaces.
|
||||
properties:
|
||||
from:
|
||||
default: None
|
||||
description: |-
|
||||
from selects which namespaces may attach. Same is equivalent to None in
|
||||
effect (same-namespace is unrestricted either way) but kept for parity
|
||||
with the upstream enum this mirrors, and to make the policy
|
||||
self-documenting in a diff.
|
||||
enum:
|
||||
- None
|
||||
- Same
|
||||
- All
|
||||
- Selector
|
||||
type: string
|
||||
selector:
|
||||
description: |-
|
||||
selector is required, and only meaningful, when from is Selector: a
|
||||
standard label selector over Namespace objects.
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: |-
|
||||
A label selector requirement is a selector that contains values, a key, and an operator that
|
||||
relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: |-
|
||||
operator represents a key's relationship to a set of values.
|
||||
Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: |-
|
||||
values is an array of string values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the operator is Exists or DoesNotExist,
|
||||
the values array must be empty. This array is replaced during a strategic
|
||||
merge patch.
|
||||
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
|
||||
description: |-
|
||||
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
type: object
|
||||
type: object
|
||||
database:
|
||||
description: |-
|
||||
DatabaseSpec is the Postgres connection this TerdutServer uses. Exactly
|
||||
one of dsn or postgresClusterRef must be set (DESIGN.md §8) — this
|
||||
operator provisions no database either way, only wires up one that
|
||||
exists.
|
||||
properties:
|
||||
dsn:
|
||||
description: |-
|
||||
dsn is a DSN with no password in it, e.g.
|
||||
"postgres://terdut@terdut-postgres:5432/terdut?sslmode=require" --
|
||||
mutually exclusive with postgresClusterRef.
|
||||
type: string
|
||||
passwordSecretRef:
|
||||
description: |-
|
||||
passwordSecretRef is where PGPASSWORD comes from for the dsn path.
|
||||
pgx falls back to libpq's environment variables for anything the DSN
|
||||
omits, so the password never appears in the DSN string itself. Unused
|
||||
on the postgresClusterRef path -- the Zalando-generated Secret is
|
||||
wired in directly instead.
|
||||
properties:
|
||||
key:
|
||||
description: key is the data key inside the Secret holding
|
||||
the raw value.
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- name
|
||||
type: object
|
||||
postgresClusterRef:
|
||||
description: |-
|
||||
postgresClusterRef names a Zalando postgres-operator CR instead of a
|
||||
plain DSN -- mutually exclusive with dsn.
|
||||
properties:
|
||||
name:
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: exactly one of dsn or postgresClusterRef must be set
|
||||
rule: '(has(self.dsn) ? 1 : 0) + (has(self.postgresClusterRef) ?
|
||||
1 : 0) == 1'
|
||||
deadman:
|
||||
description: |-
|
||||
DeadmanSpec controls dead man's switch alerts. Matchers/Timeout/Severity
|
||||
map straight to TERDUT_DEADMAN_MATCHERS/TERDUT_DEADMAN_TIMEOUT/
|
||||
TERDUT_DEADMAN_SEVERITY.
|
||||
properties:
|
||||
matchers:
|
||||
type: string
|
||||
severity:
|
||||
type: string
|
||||
timeout:
|
||||
type: string
|
||||
type: object
|
||||
image:
|
||||
description: ImageSpec is the terdut-server image to run.
|
||||
properties:
|
||||
repository:
|
||||
minLength: 1
|
||||
type: string
|
||||
tag:
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- repository
|
||||
- tag
|
||||
type: object
|
||||
networking:
|
||||
description: |-
|
||||
NetworkingSpec is how this TerdutServer is reached from outside the
|
||||
cluster.
|
||||
|
||||
hostname/gatewayListener describe the intended Gateway API HTTPRoute
|
||||
(matching charts/terdut-server's own templates/httpproxy.yaml, despite its
|
||||
name — that chart carries a Gateway API HTTPRoute, not a Contour
|
||||
HTTPProxy), but creating that HTTPRoute isn't implemented yet: it needs
|
||||
the Gateway API types as a new dependency, and nothing about proving a
|
||||
TerdutServer boots and bootstraps a real server depends on external
|
||||
ingress existing. Tracked as a near-term follow-up, not deferred to a
|
||||
later ROADMAP.md stage the way Deployment/database/bootstrap once were.
|
||||
properties:
|
||||
gatewayListener:
|
||||
description: |-
|
||||
gatewayListener is the HTTPRoute's sectionName once it exists. Empty
|
||||
attaches to every matching listener, including plaintext HTTP.
|
||||
type: string
|
||||
hostname:
|
||||
description: hostname the HTTPRoute will carry once it exists.
|
||||
type: string
|
||||
servicePort:
|
||||
default: 8080
|
||||
description: |-
|
||||
servicePort is both the Service's port and the HTTPRoute's backend
|
||||
port once it exists. Defaults to 8080, matching the chart's own
|
||||
service.port default.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
notify:
|
||||
description: |-
|
||||
NotifySpec controls push notifications via ntfy. Empty ntfyURL disables
|
||||
notifications entirely (matches the chart's own default).
|
||||
properties:
|
||||
fallbackTopic:
|
||||
type: string
|
||||
ntfyURL:
|
||||
type: string
|
||||
repeatEvery:
|
||||
type: string
|
||||
tokenSecretRef:
|
||||
description: |-
|
||||
tokenSecretRef is an optional bearer token for an access-controlled
|
||||
ntfy. Leave unset for an open ntfy.
|
||||
properties:
|
||||
key:
|
||||
description: key is the data key inside the Secret holding
|
||||
the raw value.
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
oidc:
|
||||
description: |-
|
||||
OIDCSpec controls single sign-on. Fields the chart also exposes but
|
||||
DESIGN.md's spec doesn't (usernameClaim, emailClaim, groupsClaim,
|
||||
trustEmail) use terdut-server's own defaults
|
||||
(preferred_username/email/groups/false) rather than being added here
|
||||
speculatively.
|
||||
properties:
|
||||
adminGroup:
|
||||
type: string
|
||||
allowedGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
clientID:
|
||||
type: string
|
||||
clientSecretRef:
|
||||
description: |-
|
||||
SecretKeyRef names one data key inside a Secret. Every use of this type in
|
||||
TerdutServerSpec resolves in the TerdutServer's own namespace (it's wired
|
||||
straight into the Deployment's pod spec as a secretKeyRef env source,
|
||||
which Kubernetes itself only allows same-namespace) -- unlike the
|
||||
generated credentials Secret (DESIGN.md §6), which always lives in the
|
||||
operator's own namespace and is never referenced through this type.
|
||||
properties:
|
||||
key:
|
||||
description: key is the data key inside the Secret holding
|
||||
the raw value.
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- name
|
||||
type: object
|
||||
enabled:
|
||||
type: boolean
|
||||
issuer:
|
||||
type: string
|
||||
name:
|
||||
default: SSO
|
||||
type: string
|
||||
scopes:
|
||||
default: openid profile email
|
||||
type: string
|
||||
sessionMaxAge:
|
||||
default: 12h
|
||||
type: string
|
||||
type: object
|
||||
passwordLogin:
|
||||
default: true
|
||||
description: |-
|
||||
passwordLogin: whether a user may sign in, or sign up, with a
|
||||
password.
|
||||
type: boolean
|
||||
replicas:
|
||||
default: 1
|
||||
description: |-
|
||||
replicas. terdut-server is not horizontally-scale-tested; keep this
|
||||
at its default of 1 unless you've verified otherwise -- the sweeper
|
||||
and the notifier are unsynchronised singletons.
|
||||
format: int32
|
||||
type: integer
|
||||
sweeper:
|
||||
description: |-
|
||||
SweeperSpec controls incident auto-resolve/archive timing. Values are
|
||||
Go duration strings (e.g. "6h"), passed straight through to the
|
||||
TERDUT_STALE_AFTER/TERDUT_ARCHIVE_AFTER env vars exactly as written --
|
||||
not a structured metav1.Duration, since terdut-server parses them itself
|
||||
and a round-trip through a different type would buy nothing.
|
||||
properties:
|
||||
archiveAfter:
|
||||
type: string
|
||||
staleAfter:
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- database
|
||||
- image
|
||||
- networking
|
||||
type: object
|
||||
status:
|
||||
description: status defines the observed state of TerdutServer
|
||||
properties:
|
||||
conditions:
|
||||
description: conditions represent the current state of the TerdutServer
|
||||
resource.
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
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
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
credentialsSecretRef:
|
||||
description: |-
|
||||
credentialsSecretRef is the generated instance-scoped credential
|
||||
(DESIGN.md §6) -- pure output, always in the operator's own
|
||||
namespace, under a fixed data key ("token"). Set only once
|
||||
Bootstrapped is True.
|
||||
properties:
|
||||
key:
|
||||
description: key is the data key inside the Secret holding the
|
||||
raw value.
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- name
|
||||
type: object
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration is the .metadata.generation this status was last
|
||||
computed against — the standard way a client (or `kubectl wait`)
|
||||
tells "applied" from "seen" (DESIGN.md §7).
|
||||
format: int64
|
||||
type: integer
|
||||
serviceName:
|
||||
description: |-
|
||||
serviceName is the Service this controller created for the
|
||||
Deployment, so other objects can reference it without recomputing the
|
||||
naming convention.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,198 @@
|
||||
{{- if .Values.crd.enabled }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
{{- if .Values.crd.keep }}
|
||||
"helm.sh/resource-policy": keep
|
||||
{{- end }}
|
||||
controller-gen.kubebuilder.io/version: v0.22.0
|
||||
name: terdutteams.terdut.ryuvia.com
|
||||
spec:
|
||||
group: terdut.ryuvia.com
|
||||
names:
|
||||
kind: TerdutTeam
|
||||
listKind: TerdutTeamList
|
||||
plural: terdutteams
|
||||
singular: terdutteam
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.serverRef.name
|
||||
name: Server
|
||||
type: string
|
||||
- jsonPath: .status.teamID
|
||||
name: TeamID
|
||||
type: integer
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||
name: Ready
|
||||
type: string
|
||||
- jsonPath: .status.conditions[?(@.type=="Ready")].reason
|
||||
name: Reason
|
||||
type: string
|
||||
name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: TerdutTeam is the Schema for the terdutteams API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: spec defines the desired state of TerdutTeam
|
||||
properties:
|
||||
displayName:
|
||||
description: |-
|
||||
displayName is this team's name, both in terdut-server's own data
|
||||
(POST /api/teams {"name": ...}) and as the identity POST /api/teams
|
||||
and GET /api/teams?name= correlate on (DESIGN.md §5's idempotent-
|
||||
create rule, via TEAM-LOOKUP.md).
|
||||
minLength: 1
|
||||
type: string
|
||||
oidc:
|
||||
description: |-
|
||||
TerdutTeamOIDC binds which identity-provider groups grant membership and
|
||||
ownership of this team (DESIGN.md §4.2). Both empty means no group grants
|
||||
either role here — matches terdut-server's own NULLIF-on-empty-string
|
||||
handling (internal/api/oidc_teams.go).
|
||||
properties:
|
||||
memberGroup:
|
||||
type: string
|
||||
ownerGroup:
|
||||
type: string
|
||||
type: object
|
||||
serverRef:
|
||||
description: serverRef names the TerdutServer this team belongs to.
|
||||
properties:
|
||||
name:
|
||||
minLength: 1
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- displayName
|
||||
- serverRef
|
||||
type: object
|
||||
status:
|
||||
description: status defines the observed state of TerdutTeam
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
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
|
||||
x-kubernetes-list-map-keys:
|
||||
- type
|
||||
x-kubernetes-list-type: map
|
||||
credentialsSecretRef:
|
||||
description: |-
|
||||
credentialsSecretRef is this team's own scoped credential
|
||||
(DESIGN.md §6 point 3) -- pure output, always in the operator's own
|
||||
namespace, under a fixed data key ("token").
|
||||
properties:
|
||||
key:
|
||||
description: key is the data key inside the Secret holding the
|
||||
raw value.
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is the Secret's name.
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- name
|
||||
type: object
|
||||
observedGeneration:
|
||||
format: int64
|
||||
type: integer
|
||||
serverEndpoint:
|
||||
description: |-
|
||||
serverEndpoint is the resolved TerdutServer's base URL, resolved once
|
||||
here so no child controller (TerdutEscalationRule, TerdutDeadmanSwitch,
|
||||
TerdutAlertSource) ever needs its own RBAC on terdutservers just to
|
||||
find out where to send a request (DESIGN.md §5).
|
||||
type: string
|
||||
teamID:
|
||||
description: |-
|
||||
teamID is the server-side id -- needed by every child object's
|
||||
controller (DESIGN.md §4.2).
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,161 @@
|
||||
{{- if or (not (hasKey .Values.manager "enabled")) (.Values.manager.enabled) }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
control-plane: controller-manager
|
||||
{{- with .Values.manager.labels }}
|
||||
{{- with omit . "app.kubernetes.io/managed-by" "app.kubernetes.io/name" "helm.sh/chart" "app.kubernetes.io/instance" "control-plane" }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "controller-manager" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- if .Values.manager.annotations }}
|
||||
annotations:
|
||||
{{- toYaml .Values.manager.annotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.manager.strategy }}
|
||||
strategy: {{ toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
replicas: {{ .Values.manager.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/default-container: manager
|
||||
{{- with .Values.manager.pod }}
|
||||
{{- with .annotations }}
|
||||
{{- with omit . "kubectl.kubernetes.io/default-container" }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
control-plane: controller-manager
|
||||
{{- with .Values.manager.pod }}
|
||||
{{- with .labels }}
|
||||
{{- with omit . "app.kubernetes.io/name" "helm.sh/chart" "app.kubernetes.io/instance" "app.kubernetes.io/managed-by" "control-plane" }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.manager.topologySpreadConstraints }}
|
||||
topologySpreadConstraints: {{ toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- with .Values.manager.priorityClassName }}
|
||||
priorityClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.manager.tolerations }}
|
||||
tolerations: {{ toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- with .Values.manager.affinity }}
|
||||
affinity: {{ toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- with .Values.manager.nodeSelector }}
|
||||
nodeSelector: {{ toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- with .Values.manager.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- args:
|
||||
{{- if .Values.metrics.enabled }}
|
||||
- --metrics-bind-address=:{{ .Values.metrics.port }}
|
||||
{{- if not .Values.metrics.secure }}
|
||||
- --metrics-secure=false
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
# Bind to :0 to disable the controller-runtime managed metrics server
|
||||
- --metrics-bind-address=0
|
||||
{{- end }}
|
||||
- --health-probe-bind-address=:{{ .Values.manager.healthProbe.port }}
|
||||
{{- range .Values.manager.args }}
|
||||
- {{ tpl . $ }}
|
||||
{{- end }}
|
||||
command:
|
||||
- /manager
|
||||
env:
|
||||
{{- if or .Values.manager.env (and (kindIs "map" .Values.manager.envOverrides) (not (empty .Values.manager.envOverrides))) }}
|
||||
{{- if .Values.manager.env }}
|
||||
{{- toYaml .Values.manager.env | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- if kindIs "map" .Values.manager.envOverrides }}
|
||||
{{- range $k, $v := .Values.manager.envOverrides }}
|
||||
- name: {{ $k }}
|
||||
value: {{ $v | quote }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
[]
|
||||
{{- end }}
|
||||
image: "{{ .Values.manager.image.repository | default "controller" }}{{- if not (contains "@" (.Values.manager.image.repository | default "controller")) }}:{{ .Values.manager.image.tag | default .Chart.AppVersion }}{{- end }}"
|
||||
{{- with .Values.manager.image.pullPolicy }}
|
||||
imagePullPolicy: {{ . }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: {{ .Values.manager.healthProbe.port }}
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: {{ .Values.manager.healthProbe.port }}
|
||||
name: health
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: {{ .Values.manager.healthProbe.port }}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
{{- if .Values.manager.resources }}
|
||||
{{- toYaml .Values.manager.resources | nindent 10 }}
|
||||
{{- else }}
|
||||
{}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- if .Values.manager.securityContext }}
|
||||
{{- toYaml .Values.manager.securityContext | nindent 10 }}
|
||||
{{- else }}
|
||||
{}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.manager.extraVolumeMounts }}
|
||||
{{- toYaml .Values.manager.extraVolumeMounts | nindent 10 }}
|
||||
{{- else }}
|
||||
[]
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- if .Values.manager.podSecurityContext }}
|
||||
{{- toYaml .Values.manager.podSecurityContext | nindent 8 }}
|
||||
{{- else }}
|
||||
{}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "terdut-operator.serviceAccountName" . }}
|
||||
{{- if and (hasKey .Values.manager "terminationGracePeriodSeconds") (ne .Values.manager.terminationGracePeriodSeconds nil) }}
|
||||
terminationGracePeriodSeconds: {{ .Values.manager.terminationGracePeriodSeconds }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if .Values.manager.extraVolumes }}
|
||||
{{- toYaml .Values.manager.extraVolumes | nindent 8 }}
|
||||
{{- else }}
|
||||
[]
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,22 @@
|
||||
{{- if .Values.metrics.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
control-plane: controller-manager
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "controller-manager-metrics-service" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
ports:
|
||||
- name: {{ if .Values.metrics.secure }}https{{ else }}http{{ end }}
|
||||
port: {{ .Values.metrics.port }}
|
||||
protocol: TCP
|
||||
targetPort: {{ .Values.metrics.port }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
control-plane: controller-manager
|
||||
{{- end }}
|
||||
@@ -0,0 +1,25 @@
|
||||
{{- if and .Values.networkPolicy.enabled .Values.metrics.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "allow-metrics-traffic" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
metrics: enabled
|
||||
ports:
|
||||
- port: {{ .Values.metrics.port }}
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
@@ -0,0 +1,53 @@
|
||||
{{- if .Values.prometheus.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
control-plane: controller-manager
|
||||
{{- with .Values.prometheus.labels }}
|
||||
{{- with omit . "app.kubernetes.io/managed-by" "app.kubernetes.io/name" "helm.sh/chart" "app.kubernetes.io/instance" "control-plane" }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.prometheus.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "controller-manager-metrics-monitor" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
endpoints:
|
||||
- {{- if .Values.metrics.secure }}
|
||||
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
{{- end }}
|
||||
path: /metrics
|
||||
port: {{ if .Values.metrics.secure }}https{{ else }}http{{ end }}
|
||||
scheme: {{ if .Values.metrics.secure }}https{{ else }}http{{ end }}
|
||||
{{- if .Values.metrics.secure }}
|
||||
tlsConfig:
|
||||
serverName: {{ include "terdut-operator.resourceName" (dict "suffix" "controller-manager-metrics-service" "context" $) }}.{{ .Release.Namespace }}.svc
|
||||
{{- if .Values.certManager.enabled }}
|
||||
ca:
|
||||
secret:
|
||||
name: metrics-server-cert
|
||||
key: ca.crt
|
||||
cert:
|
||||
secret:
|
||||
name: metrics-server-cert
|
||||
key: tls.crt
|
||||
keySecret:
|
||||
name: metrics-server-cert
|
||||
key: tls.key
|
||||
{{- else }}
|
||||
insecureSkipVerify: true
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
control-plane: controller-manager
|
||||
{{- end }}
|
||||
@@ -0,0 +1,21 @@
|
||||
{{- if .Values.serviceAccount.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with .Values.serviceAccount.labels }}
|
||||
{{- with omit . "app.kubernetes.io/managed-by" "app.kubernetes.io/name" "helm.sh/chart" "app.kubernetes.io/instance" }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
name: {{ include "terdut-operator.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,42 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "leader-election-role" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "leader-election-rolebinding" "context" $) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "leader-election-role" "context" $) }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "terdut-operator.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -0,0 +1,98 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "manager-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- services
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- acid.zalan.do
|
||||
resources:
|
||||
- postgresqls
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- deployments
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- events.k8s.io
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources
|
||||
- terdutdeadmanswitches
|
||||
- terdutescalationrules
|
||||
- terdutservers
|
||||
- terdutteams
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources/finalizers
|
||||
- terdutdeadmanswitches/finalizers
|
||||
- terdutescalationrules/finalizers
|
||||
- terdutservers/finalizers
|
||||
- terdutteams/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources/status
|
||||
- terdutdeadmanswitches/status
|
||||
- terdutescalationrules/status
|
||||
- terdutservers/status
|
||||
- terdutteams/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
@@ -0,0 +1,28 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: RoleBinding
|
||||
{{- else }}
|
||||
kind: ClusterRoleBinding
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "manager-rolebinding" "context" $) }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "manager-role" "context" $) }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "terdut-operator.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -0,0 +1,19 @@
|
||||
{{- if and .Values.metrics.enabled .Values.metrics.secure }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "metrics-auth-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
{{- end }}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{- if and .Values.metrics.enabled .Values.metrics.secure }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "metrics-auth-rolebinding" "context" $) }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "metrics-auth-role" "context" $) }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "terdut-operator.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,11 @@
|
||||
{{- if and .Values.metrics.enabled .Values.metrics.secure }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "metrics-reader" "context" $) }}
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutalertsource-admin-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutalertsource-editor-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutalertsource-viewer-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutalertsources/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutdeadmanswitch-admin-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutdeadmanswitch-editor-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutdeadmanswitch-viewer-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutdeadmanswitches/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutescalationrule-admin-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutescalationrule-editor-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutescalationrule-viewer-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutescalationrules/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutserver-admin-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutserver-editor-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutserver-viewer-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutservers/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutteam-admin-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutteam-editor-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.rbac.helpers.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
kind: Role
|
||||
{{- else }}
|
||||
kind: ClusterRole
|
||||
{{- end }}
|
||||
metadata:
|
||||
{{- if .Values.rbac.namespaced }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ include "terdut-operator.resourceName" (dict "suffix" "terdutteam-viewer-role" "context" $) }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- terdut.ryuvia.com
|
||||
resources:
|
||||
- terdutteams/status
|
||||
verbs:
|
||||
- get
|
||||
{{- end }}
|
||||
@@ -0,0 +1,54 @@
|
||||
{{/*
|
||||
Optional: one TerdutServer CR from values.yaml (DESIGN.md §10's "helm
|
||||
install and get a server" path). Off by default -- see values.yaml's own
|
||||
terdutServer block for the full shape and api/v1alpha1/terdutserver_types.go
|
||||
for what each field validates.
|
||||
*/}}
|
||||
{{- if .Values.terdutServer.enabled }}
|
||||
apiVersion: terdut.ryuvia.com/v1alpha1
|
||||
kind: TerdutServer
|
||||
metadata:
|
||||
name: {{ .Values.terdutServer.name | default (include "terdut-operator.fullname" .) }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/name: {{ include "terdut-operator.name" . }}
|
||||
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
image:
|
||||
repository: {{ required "terdutServer.image.repository is required when terdutServer.enabled" .Values.terdutServer.image.repository }}
|
||||
tag: {{ required "terdutServer.image.tag is required when terdutServer.enabled" .Values.terdutServer.image.tag | quote }}
|
||||
replicas: {{ .Values.terdutServer.replicas }}
|
||||
networking:
|
||||
hostname: {{ required "terdutServer.networking.hostname is required when terdutServer.enabled" .Values.terdutServer.networking.hostname | quote }}
|
||||
servicePort: {{ .Values.terdutServer.networking.servicePort }}
|
||||
# Not re-validated here as dsn-xor-postgresClusterRef (api/v1alpha1's own
|
||||
# CEL rule on DatabaseSpec is the authority, same v1 stance as every
|
||||
# other cross-field check in this operator -- DESIGN.md §13: no
|
||||
# admission webhooks, CEL-only validation). This chart just has to pass
|
||||
# the block through faithfully.
|
||||
database:
|
||||
{{- required "terdutServer.database (dsn or postgresClusterRef) is required when terdutServer.enabled" .Values.terdutServer.database | toYaml | nindent 4 }}
|
||||
{{- with .Values.terdutServer.sweeper }}
|
||||
sweeper:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.terdutServer.deadman }}
|
||||
deadman:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.terdutServer.notify }}
|
||||
notify:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.terdutServer.oidc }}
|
||||
oidc:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
passwordLogin: {{ .Values.terdutServer.passwordLogin }}
|
||||
{{- with .Values.terdutServer.allowedTeams }}
|
||||
allowedTeams:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,272 @@
|
||||
## String to partially override chart.fullname template (will maintain the release name)
|
||||
##
|
||||
# nameOverride: ""
|
||||
|
||||
## String to fully override chart.fullname template
|
||||
##
|
||||
# fullnameOverride: ""
|
||||
|
||||
## Configure the controller manager deployment
|
||||
##
|
||||
manager:
|
||||
## Set to false to skip manager installation
|
||||
##
|
||||
enabled: true
|
||||
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
repository: git.ryuvia.com/niklas/terdut-operator
|
||||
## Image tag (defaults to Chart.appVersion if not set) -- the release
|
||||
## process (`make helm-package`) always passes --app-version from the
|
||||
## tag, so leaving this unset here is what tracks a release correctly.
|
||||
##
|
||||
# tag: ""
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
## Arguments
|
||||
##
|
||||
args:
|
||||
- --leader-elect
|
||||
|
||||
## Health probes.
|
||||
## The manager serves the liveness (/healthz) and readiness (/readyz) endpoints on this port.
|
||||
##
|
||||
healthProbe:
|
||||
# Health probe server port
|
||||
port: 8081
|
||||
|
||||
## Environment variables
|
||||
##
|
||||
env:
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
|
||||
## Env overrides (--set manager.envOverrides.VAR=value)
|
||||
## Same name in env above: this value takes precedence.
|
||||
##
|
||||
envOverrides: {}
|
||||
|
||||
## Image pull secrets
|
||||
##
|
||||
# imagePullSecrets:
|
||||
# - name: myregistrykey
|
||||
|
||||
## Pod-level security settings
|
||||
##
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
## Container-level security settings
|
||||
##
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
|
||||
## Resource limits and requests
|
||||
##
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
|
||||
## Manager pod's affinity
|
||||
##
|
||||
affinity: {}
|
||||
|
||||
## Manager pod's node selector
|
||||
##
|
||||
nodeSelector: {}
|
||||
|
||||
## Manager pod's tolerations
|
||||
##
|
||||
tolerations: []
|
||||
|
||||
## Deployment strategy
|
||||
##
|
||||
# strategy:
|
||||
# type: RollingUpdate
|
||||
# rollingUpdate:
|
||||
# maxSurge: 25%
|
||||
# maxUnavailable: 25%
|
||||
|
||||
## Priority class name
|
||||
##
|
||||
# priorityClassName: ""
|
||||
|
||||
## Topology spread constraints
|
||||
##
|
||||
# topologySpreadConstraints: []
|
||||
|
||||
## Termination grace period seconds
|
||||
##
|
||||
terminationGracePeriodSeconds: 10
|
||||
|
||||
## Custom Deployment labels
|
||||
##
|
||||
# labels: {}
|
||||
|
||||
## Custom Deployment annotations
|
||||
##
|
||||
# annotations: {}
|
||||
|
||||
## Custom Pod labels and annotations
|
||||
##
|
||||
# pod:
|
||||
# labels: {}
|
||||
# annotations: {}
|
||||
|
||||
## RBAC configuration
|
||||
##
|
||||
rbac:
|
||||
## RBAC resource scope
|
||||
## - false (default): ClusterRole/ClusterRoleBinding (all namespaces)
|
||||
## - true: Role/RoleBinding (release namespace only)
|
||||
##
|
||||
namespaced: false
|
||||
|
||||
## Helper roles for CRD management (admin/editor/viewer)
|
||||
##
|
||||
helpers:
|
||||
## Install convenience admin/editor/viewer roles for CRDs
|
||||
##
|
||||
enabled: false
|
||||
|
||||
## ServiceAccount configuration
|
||||
##
|
||||
serviceAccount:
|
||||
# Install default ServiceAccount provided
|
||||
enabled: true
|
||||
|
||||
## Existing ServiceAccount name (required when enabled=false)
|
||||
## Set to "default" to use the namespace default ServiceAccount
|
||||
## Note: When enabled=true, respects nameOverride/fullnameOverride
|
||||
##
|
||||
# name: ""
|
||||
|
||||
## Custom ServiceAccount annotations
|
||||
##
|
||||
# annotations: {}
|
||||
|
||||
## Custom ServiceAccount labels
|
||||
##
|
||||
# labels: {}
|
||||
|
||||
## Custom Resource Definitions
|
||||
##
|
||||
crd:
|
||||
# Install CRDs with the chart
|
||||
enabled: true
|
||||
# Keep CRDs when uninstalling
|
||||
keep: true
|
||||
|
||||
## Controller metrics endpoint.
|
||||
## Enable to expose /metrics endpoint
|
||||
##
|
||||
metrics:
|
||||
enabled: true
|
||||
# Metrics server port
|
||||
port: 8443
|
||||
# Enable secure metrics: HTTPS with certs/auth (true) or HTTP (false).
|
||||
# Note: Metrics authn/authz needs ClusterRole access.
|
||||
secure: true
|
||||
|
||||
## Cert-manager integration for TLS certificates.
|
||||
## Required for webhook certificates and metrics endpoint certificates.
|
||||
##
|
||||
certManager:
|
||||
enabled: false
|
||||
|
||||
## Webhook server configuration
|
||||
##
|
||||
webhook:
|
||||
enabled: false
|
||||
# Webhook server port
|
||||
port: 9443
|
||||
|
||||
## Prometheus ServiceMonitor for metrics scraping.
|
||||
## Requires prometheus-operator to be installed in the cluster.
|
||||
##
|
||||
prometheus:
|
||||
enabled: false
|
||||
|
||||
## Custom ServiceMonitor labels
|
||||
##
|
||||
# labels: {}
|
||||
|
||||
## Custom ServiceMonitor annotations
|
||||
##
|
||||
# annotations: {}
|
||||
|
||||
## Network policies for controlling traffic flow.
|
||||
## Enable to restrict ingress to the controller manager.
|
||||
##
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
|
||||
## Optionally render one TerdutServer CR from this chart -- "helm install
|
||||
## and get a server" without hand-writing a CR (DESIGN.md §10). Off by
|
||||
## default: most installs only want the operator and CRDs here, then apply
|
||||
## their own TerdutServer (and TerdutTeam, and so on) separately. The shape
|
||||
## below mirrors api/v1alpha1/terdutserver_types.go's TerdutServerSpec
|
||||
## directly -- see that file for what each field means and which are
|
||||
## required.
|
||||
##
|
||||
terdutServer:
|
||||
enabled: false
|
||||
|
||||
## This CR's own metadata.name. Defaults to the chart's own fullname if unset.
|
||||
# name: ""
|
||||
|
||||
image:
|
||||
repository: git.ryuvia.com/niklas/terdut-server
|
||||
## Required when terdutServer.enabled.
|
||||
# tag: ""
|
||||
|
||||
replicas: 1
|
||||
|
||||
networking:
|
||||
## Required when terdutServer.enabled -- the hostname a future
|
||||
## HTTPRoute will carry (see NetworkingSpec's own doc comment: creating
|
||||
## that HTTPRoute isn't implemented yet).
|
||||
# hostname: ""
|
||||
servicePort: 8080
|
||||
|
||||
## Exactly one of dsn or postgresClusterRef, matching DatabaseSpec's own
|
||||
## CEL rule -- required when terdutServer.enabled. Bring-your-own DSN:
|
||||
## database:
|
||||
## dsn: "postgres://terdut@terdut-postgres:5432/terdut?sslmode=require"
|
||||
## passwordSecretRef:
|
||||
## name: terdut-postgres-password
|
||||
## key: password
|
||||
## Zalando postgres-operator instead:
|
||||
## database:
|
||||
## postgresClusterRef:
|
||||
## name: terdut-postgres
|
||||
database: {}
|
||||
|
||||
## All optional -- omit entirely for their terdut-server defaults.
|
||||
# sweeper:
|
||||
# staleAfter: 6h
|
||||
# archiveAfter: 168h
|
||||
# deadman:
|
||||
# matchers: "alertname=Watchdog"
|
||||
# timeout: 15m
|
||||
# severity: critical
|
||||
# notify: {}
|
||||
# oidc: {}
|
||||
|
||||
passwordLogin: true
|
||||
|
||||
# allowedTeams: {}
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
resources:
|
||||
- manager.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: controller
|
||||
newTag: latest
|
||||
|
||||
@@ -12,7 +12,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.25.1 // indirect
|
||||
cel.dev/expr v0.25.2 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
@@ -88,7 +88,7 @@ require (
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||
google.golang.org/grpc v1.82.1 // indirect
|
||||
google.golang.org/grpc v1.83.1 // indirect
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
|
||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||
@@ -222,8 +222,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
|
||||
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
|
||||
google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y=
|
||||
google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
Reference in New Issue
Block a user