-
Notifications
You must be signed in to change notification settings - Fork 265
[WIP] CNTRLPLANE-3234: health monitor #2193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Disposable image for the KIND harness. Build from the LIBRARY-GO | ||
| # MODULE ROOT so the context includes vendor/ and go.mod: | ||
| # docker build -f examples/kms-health-kind/Dockerfile.fake-plugin -t kms-health-kind-fake-plugin:dev . | ||
| FROM golang:1.25 AS build | ||
| WORKDIR /src | ||
| COPY . . | ||
| RUN CGO_ENABLED=0 GOFLAGS=-mod=vendor \ | ||
| go build -trimpath -ldflags='-s -w' \ | ||
| -o /out/fake-plugin \ | ||
| ./examples/kms-health-kind/fake-plugin | ||
|
|
||
| FROM gcr.io/distroless/static:nonroot | ||
| COPY --from=build /out/fake-plugin /fake-plugin | ||
| USER nonroot:nonroot | ||
| ENTRYPOINT ["/fake-plugin"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Disposable image for the KIND harness. Build from the LIBRARY-GO | ||
| # MODULE ROOT so the context includes vendor/ and go.mod: | ||
| # docker build -f examples/kms-health-kind/Dockerfile.monitor -t kms-health-kind-monitor:dev . | ||
| FROM golang:1.25 AS build | ||
| WORKDIR /src | ||
| COPY . . | ||
| RUN CGO_ENABLED=0 GOFLAGS=-mod=vendor \ | ||
| go build -trimpath -ldflags='-s -w' \ | ||
| -o /out/monitor \ | ||
| ./examples/kms-health-kind/cmd/monitor | ||
|
|
||
| FROM gcr.io/distroless/static:nonroot | ||
| COPY --from=build /out/monitor /monitor | ||
| USER nonroot:nonroot | ||
| ENTRYPOINT ["/monitor"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # KMSv2 health-monitor KIND harness. Disposable. | ||
| # | ||
| # All targets should be run from the library-go module root: | ||
| # make -C examples/kms-health-kind kind-verify | ||
|
|
||
| CLUSTER ?= kms-health-claude | ||
| IMAGE_FAKE_PLUGIN ?= kms-health-kind-fake-plugin:dev | ||
| IMAGE_MONITOR ?= kms-health-kind-monitor:dev | ||
| CTX := kind-$(CLUSTER) | ||
| NODE := $(CLUSTER)-control-plane | ||
| FAKE_POD := kms-fake-plugin-$(NODE) | ||
|
|
||
| # Dockerfile build context = library-go module root (need vendor/, go.mod). | ||
| REPO_ROOT := $(shell cd ../.. && pwd -P) | ||
| HARNESS_DIR := $(shell pwd -P) | ||
|
|
||
| .PHONY: build-images | ||
| build-images: | ||
| docker build -t $(IMAGE_FAKE_PLUGIN) \ | ||
| -f $(HARNESS_DIR)/Dockerfile.fake-plugin \ | ||
| $(REPO_ROOT) | ||
| docker build -t $(IMAGE_MONITOR) \ | ||
| -f $(HARNESS_DIR)/Dockerfile.monitor \ | ||
| $(REPO_ROOT) | ||
|
|
||
| .PHONY: kind-up | ||
| kind-up: | ||
| CLUSTER=$(CLUSTER) $(HARNESS_DIR)/bin/up.sh | ||
|
|
||
| .PHONY: kind-down | ||
| kind-down: | ||
| CLUSTER=$(CLUSTER) $(HARNESS_DIR)/bin/down.sh | ||
|
|
||
| ## Distroless fake-plugin has no touch/rm; flip via node /tmp (bind-mounted | ||
| ## to /var/run/kmsplugin-fake/ in both pods). | ||
| .PHONY: flip-unhealthy | ||
| flip-unhealthy: | ||
| docker exec $(NODE) touch /tmp/kms-unhealthy | ||
|
|
||
| .PHONY: flip-healthy | ||
| flip-healthy: | ||
| docker exec $(NODE) rm -f /tmp/kms-unhealthy | ||
|
|
||
| ## Drift check: diff output against monitor-deployment.yaml's container block. | ||
| .PHONY: render-container | ||
| render-container: | ||
| go run $(REPO_ROOT)/examples/kms-health-kind/cmd/render-container \ | ||
| --kms-plugin-name=fake \ | ||
| --image=$(IMAGE_MONITOR) \ | ||
| --command=/usr/bin/kms-health-monitor \ | ||
| --probe-interval=2s \ | ||
| --probe-interval-unhealthy=1s \ | ||
| --probe-timeout=1s \ | ||
| --write-timeout=5s \ | ||
| --configmap-namespace=kms-health-test | ||
|
|
||
| .PHONY: verify | ||
| verify: | ||
| CLUSTER=$(CLUSTER) $(HARNESS_DIR)/verify.sh | ||
|
|
||
| .PHONY: kind-verify | ||
| kind-verify: build-images kind-up verify | ||
| @echo "" | ||
| @echo "=================================================" | ||
| @echo " kind-verify PASSED on cluster ${CLUSTER}" | ||
| @echo " tear down with: make kind-down" | ||
| @echo "=================================================" | ||
|
|
||
| .PHONY: cm | ||
| cm: | ||
| kubectl --context $(CTX) -n kms-health-test get cm kms-health-fake -o yaml | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # Tear down the KIND cluster created by up.sh. Safe to re-run. | ||
|
|
||
| set -o errexit | ||
| set -o nounset | ||
| set -o pipefail | ||
|
|
||
| unset KIND_EXPERIMENTAL_PROVIDER | ||
|
|
||
| CLUSTER="${CLUSTER:-kms-health-claude}" | ||
|
|
||
| if kind get clusters 2>/dev/null | grep -qx "${CLUSTER}"; then | ||
| echo "[down.sh] deleting kind cluster ${CLUSTER}" | ||
| kind delete cluster --name "${CLUSTER}" | ||
| else | ||
| echo "[down.sh] cluster ${CLUSTER} not found — nothing to do" | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # Create a KIND cluster named ${CLUSTER} (default: kms-health-claude) | ||
| # with a KMSv2 fake plugin (static pod) and a health-monitor Deployment | ||
| # pinned to the control-plane node. Self-contained — doesn't depend on | ||
| # kubernetes/kubernetes/hack/local-up-kms. | ||
| # | ||
| # Run from the library-go module root. | ||
|
|
||
| set -o errexit | ||
| set -o nounset | ||
| set -o pipefail | ||
|
|
||
| # Force docker — this harness's Dockerfiles build with `docker build` | ||
| # and `kind load docker-image` needs the same backend. User may have | ||
| # KIND_EXPERIMENTAL_PROVIDER=podman set globally; unset locally. | ||
| unset KIND_EXPERIMENTAL_PROVIDER | ||
|
|
||
| CLUSTER="${CLUSTER:-kms-health-claude}" | ||
| KIND_NODE_IMAGE="${KIND_NODE_IMAGE:-kindest/node:v1.33.0}" | ||
|
|
||
| HARNESS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" | ||
|
|
||
| echo "[up.sh] cluster=${CLUSTER} node=${KIND_NODE_IMAGE}" | ||
| echo "[up.sh] harness-dir=${HARNESS_DIR}" | ||
|
|
||
| # kind.yaml uses paths relative to the harness dir (manifests/...). | ||
| cd "${HARNESS_DIR}" | ||
|
|
||
| # 1) Create the cluster (idempotent). | ||
| if kind get clusters 2>/dev/null | grep -qx "${CLUSTER}"; then | ||
| echo "[up.sh] cluster ${CLUSTER} already exists, reusing" | ||
| else | ||
| echo "[up.sh] creating kind cluster ${CLUSTER}" | ||
| kind create cluster \ | ||
| --name "${CLUSTER}" \ | ||
| --image "${KIND_NODE_IMAGE}" \ | ||
| --config manifests/kind.yaml | ||
| fi | ||
|
|
||
| CTX="kind-${CLUSTER}" | ||
| NODE="${CLUSTER}-control-plane" | ||
| STATIC_POD="kms-fake-plugin-${NODE}" | ||
|
|
||
| # 2) Load our local images. | ||
| echo "[up.sh] loading images into cluster" | ||
| kind load docker-image kms-health-kind-fake-plugin:dev --name "${CLUSTER}" | ||
| kind load docker-image kms-health-kind-monitor:dev --name "${CLUSTER}" | ||
|
|
||
| # 3) Force the static pod to restart so it picks up the freshly-loaded | ||
| # image (kubelet may have cached an ErrImageNeverPull from before). | ||
| echo "[up.sh] bouncing fake-plugin container so it picks up loaded image" | ||
| FAKE_CID="$(docker exec "${NODE}" crictl ps --name fake-plugin -q 2>/dev/null | head -1 || true)" | ||
| if [ -n "${FAKE_CID}" ]; then | ||
| docker exec "${NODE}" crictl stop "${FAKE_CID}" >/dev/null || true | ||
| fi | ||
|
|
||
| # 4) Apply namespace + RBAC + monitor Deployment. The status ConfigMap | ||
| # is created by the writer itself on first observation; nothing | ||
| # pre-creates it. | ||
| echo "[up.sh] applying namespace, RBAC, monitor Deployment" | ||
| kubectl --context "${CTX}" apply -f manifests/namespace.yaml | ||
| kubectl --context "${CTX}" apply -f manifests/rbac.yaml | ||
| kubectl --context "${CTX}" apply -f manifests/monitor-deployment.yaml | ||
|
|
||
| # 5) Wait for the monitor Deployment to be Available. Apiserver is NOT | ||
| # wired to KMS here (see manifests/kind.yaml) — we're only | ||
| # validating the monitor, not apiserver/KMS integration. | ||
| echo "[up.sh] waiting for monitor Deployment" | ||
| kubectl --context "${CTX}" -n kms-health-test rollout status deployment/kms-health-monitor-fake --timeout=120s | ||
|
Comment on lines
+50
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait for the fake plugin to come back before rolling out the monitor. After 🤖 Prompt for AI Agents |
||
|
|
||
| MONITOR_POD="$(kubectl --context "${CTX}" -n kms-health-test get pod \ | ||
| -l app=kms-health-monitor-fake \ | ||
| -o jsonpath='{.items[0].metadata.name}')" | ||
| echo "[up.sh] done." | ||
| echo " cluster: ${CLUSTER}" | ||
| echo " monitor pod: ${MONITOR_POD} (kms-health-test)" | ||
| echo " status cm: kms-health-fake (kms-health-test)" | ||
| echo " fake plugin: ${STATIC_POD} (kube-system, static)" | ||
| echo "" | ||
| echo "Try:" | ||
| echo " kubectl --context ${CTX} -n kms-health-test get cm kms-health-fake -o yaml" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // Command monitor is the throwaway KIND-stage binary that bundles | ||
| // library-go's health.NewCommand(). Production builds come from the | ||
| // OpenShift operator repos; this main exists only so the KIND harness | ||
| // has something to put in a Dockerfile. | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
|
|
||
| genericapiserver "k8s.io/apiserver/pkg/server" | ||
| "k8s.io/klog/v2" | ||
|
|
||
| "github.com/openshift/library-go/pkg/operator/encryption/kms/health" | ||
| ) | ||
|
|
||
| func main() { | ||
| ctx := genericapiserver.SetupSignalContext() | ||
| cmd := health.NewCommand(ctx) | ||
| if err := cmd.ExecuteContext(ctx); err != nil { | ||
| fmt.Fprintln(os.Stderr, err) | ||
| klog.Flush() | ||
| os.Exit(1) | ||
| } | ||
| klog.Flush() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // Disposable CLI: prints what health.GenerateContainerTemplate emits, so | ||
| // the KIND harness validates the production template end-to-end. | ||
| package main | ||
|
|
||
| import ( | ||
| "flag" | ||
| "fmt" | ||
| "os" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "sigs.k8s.io/yaml" | ||
|
|
||
| "github.com/openshift/library-go/pkg/operator/encryption/kms/health" | ||
| ) | ||
|
|
||
| func main() { | ||
| var ( | ||
| pluginName = flag.String("kms-plugin-name", "", | ||
| "DNS-1123 label identifying the plugin instance (required)") | ||
| image = flag.String("image", "", "operator image (required)") | ||
| cmdStr = flag.String("command", "", | ||
| "operator binary command, comma-separated (required), e.g. /usr/bin/kms-health-monitor") | ||
| probeInterval = flag.Duration("probe-interval", 60*time.Second, "") | ||
| probeIntervalUnhealthy = flag.Duration("probe-interval-unhealthy", 10*time.Second, "") | ||
| probeTimeout = flag.Duration("probe-timeout", 3*time.Second, "") | ||
| writeTimeout = flag.Duration("write-timeout", 5*time.Second, "") | ||
| ns = flag.String("configmap-namespace", "", | ||
| "operand namespace (required)") | ||
| ) | ||
| flag.Parse() | ||
|
|
||
| var cmdParts []string | ||
| if *cmdStr != "" { | ||
| cmdParts = strings.Split(*cmdStr, ",") | ||
| } | ||
|
|
||
| container, err := health.GenerateContainerTemplate(health.ContainerOptions{ | ||
| KMSPluginName: *pluginName, | ||
| OperatorImage: *image, | ||
| OperatorCommand: cmdParts, | ||
| ProbeInterval: *probeInterval, | ||
| ProbeIntervalUnhealthy: *probeIntervalUnhealthy, | ||
| ProbeTimeout: *probeTimeout, | ||
| WriteTimeout: *writeTimeout, | ||
| ConfigMapNamespace: *ns, | ||
| }) | ||
| if err != nil { | ||
| fmt.Fprintln(os.Stderr, "render-container:", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| out, err := yaml.Marshal(&container) | ||
| if err != nil { | ||
| fmt.Fprintln(os.Stderr, "render-container: marshal:", err) | ||
| os.Exit(1) | ||
| } | ||
| if _, err := os.Stdout.Write(out); err != nil { | ||
| fmt.Fprintln(os.Stderr, "render-container: write:", err) | ||
| os.Exit(1) | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.