diff --git a/.claude/rules/extensions-setup.md b/.claude/rules/extensions-setup.md new file mode 100644 index 000000000..7cc4d5516 --- /dev/null +++ b/.claude/rules/extensions-setup.md @@ -0,0 +1,44 @@ +# Extensions Setup + +Extensions are custom controller binaries injected into the Kuadrant operator container. They are opt-in via `INSTALL_EXTENSIONS=true` (disabled by default). + +## How it works + +The `deploy-extensions` target: +1. Applies CRDs and RBAC from `EXTENSIONS_MANIFESTS` file +2. Patches `kuadrant-operator-controller-manager` deployment with: + - An `emptyDir` volume (`extensions-binary-volume`) + - An init container (`copy-extensions`) that copies binaries from `EXTENSIONS_IMAGE` into the volume + - A volume mount at `/extensions` in the manager container + +This replicates the OCP helm-charts-olm extension patch, but targets the Kubernetes Deployment directly instead of an OLM CSV. + +## Environment variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `INSTALL_EXTENSIONS` | `false` | Enable extension deployment | +| `EXTENSIONS_IMAGE` | `quay.io/kuadrant/internal-extensions:latest` | Container image with extension binaries | +| `EXTENSIONS_MANIFESTS` | `./extensions-manifests.yaml` | Path to extension manifests (CRDs, RBAC) | + +## Usage + +```bash +# With extensions (manifests stored locally in repo root) +INSTALL_EXTENSIONS=true make local-setup + +# With extensions, manifests stored elsewhere +INSTALL_EXTENSIONS=true EXTENSIONS_MANIFESTS=~/my-extensions/manifests.yaml make local-setup + +# Custom extensions image +INSTALL_EXTENSIONS=true EXTENSIONS_IMAGE=quay.io/myorg/my-extensions:dev make local-setup + +# Deploy extensions to an existing cluster (after operator is already running) +INSTALL_EXTENSIONS=true make deploy-extensions +``` + +## Manifests file format + +The `extensions-manifests.yaml` must contain standard multi-document Kubernetes YAML (separated by `---`), not the OCP `extensionsManifests:` wrapper format. The file is `.gitignore`d since its content is user-specific. + +If `INSTALL_EXTENSIONS=true` but the manifests file doesn't exist, setup fails with an error. \ No newline at end of file diff --git a/.gitignore b/.gitignore index 614447604..250f4d9cf 100644 --- a/.gitignore +++ b/.gitignore @@ -134,5 +134,8 @@ dmypy.json logs/* !logs/.gitkeep +# Extension manifests (user-specific content) +extensions-manifests.yaml + # macOS system files .DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index 123380543..8526b103a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,6 +26,10 @@ KUADRANT_DEPLOY_MODE=helm make local-setup # Disable Prometheus if not needed (enabled by default) INSTALL_PROMETHEUS=false make local-setup +# Enable extensions (disabled by default, requires extensions-manifests.yaml in repo root) +# Override defaults with EXTENSIONS_IMAGE and EXTENSIONS_MANIFESTS if needed +INSTALL_EXTENSIONS=true make local-setup + # Apply additional manifests during setup (e.g., DNS credentials, secrets) ADDITIONAL_MANIFESTS=./my-secrets.yaml make local-setup diff --git a/make/kuadrant.mk b/make/kuadrant.mk index 13dd3bbc4..85335dd72 100644 --- a/make/kuadrant.mk +++ b/make/kuadrant.mk @@ -88,3 +88,29 @@ deploy-kuadrant-cr: ## Deploy Kuadrant CR (composed from INSTALL_PROMETHEUS and } | kubectl apply -f - kubectl wait kuadrant/kuadrant-sample --for=condition=Ready=True -n $(KUADRANT_NAMESPACE) --timeout=$(KUADRANT_CR_TIMEOUT) @echo "Kuadrant CR ready" + +.PHONY: deploy-extensions +deploy-extensions: ## Deploy Kuadrant extensions (init container + manifests) + @if [ ! -f "$(EXTENSIONS_MANIFESTS)" ]; then \ + echo "ERROR: Extensions manifest file not found: $(EXTENSIONS_MANIFESTS)"; \ + echo "Create the file or set EXTENSIONS_MANIFESTS to a valid path."; \ + exit 1; \ + fi + @echo "Applying extension manifests from $(EXTENSIONS_MANIFESTS)..." + kubectl apply -f $(EXTENSIONS_MANIFESTS) + @echo "Patching kuadrant-operator-controller-manager with extensions init container..." + kubectl patch deployment kuadrant-operator-controller-manager \ + -n $(KUADRANT_NAMESPACE) --type=strategic -p='{ \ + "spec": {"template": {"spec": { \ + "volumes": [{"name": "extensions-binary-volume", "emptyDir": {}}], \ + "containers": [{"name": "manager", \ + "volumeMounts": [{"mountPath": "/extensions", "name": "extensions-binary-volume"}]}], \ + "initContainers": [{"name": "copy-extensions", \ + "command": ["cp", "-r", "/extensions/.", "/export"], \ + "image": "$(EXTENSIONS_IMAGE)", \ + "imagePullPolicy": "Always", \ + "volumeMounts": [{"mountPath": "/export", "name": "extensions-binary-volume"}]}] \ + }}}}' + @echo "Waiting for operator rollout..." + kubectl -n $(KUADRANT_NAMESPACE) rollout status deployment/kuadrant-operator-controller-manager --timeout=$(KUBECTL_TIMEOUT) + @echo "Extensions deployed successfully" diff --git a/make/local-setup.mk b/make/local-setup.mk index 1de28ccd2..2b723b4d5 100644 --- a/make/local-setup.mk +++ b/make/local-setup.mk @@ -29,6 +29,9 @@ ifeq ($(GATEWAYAPI_PROVIDER),istio) endif endif $(MAKE) deploy-kuadrant-operator +ifeq ($(INSTALL_EXTENSIONS),true) + $(MAKE) deploy-extensions +endif $(MAKE) deploy-kuadrant-cr @echo "" @echo "Local environment setup complete!" @@ -44,6 +47,9 @@ ifeq ($(INSTALL_PROMETHEUS),true) endif ifeq ($(INSTALL_TRACING),true) @echo " Tracing: Enabled" +endif +ifeq ($(INSTALL_EXTENSIONS),true) + @echo " Extensions: Enabled (image: $(EXTENSIONS_IMAGE))" endif @echo "" @echo "Run tests with: make kuadrant" diff --git a/make/vars.mk b/make/vars.mk index 40dc9459e..3908c7334 100644 --- a/make/vars.mk +++ b/make/vars.mk @@ -52,6 +52,11 @@ ifeq ($(INSTALL_TRACING),true) KUADRANT_OPERATOR_ENV_VARS := $(KUADRANT_OPERATOR_ENV_VARS),OTEL_EXPORTER_OTLP_ENDPOINT=$(JAEGER_COLLECTOR_ENDPOINT),OTEL_EXPORTER_OTLP_INSECURE=true,LOG_LEVEL=debug endif +# Extensions configuration +INSTALL_EXTENSIONS ?= false +EXTENSIONS_IMAGE ?= quay.io/kuadrant/internal-extensions:latest +EXTENSIONS_MANIFESTS ?= ./extensions-manifests.yaml + # Timeout configurations (in seconds) KUBECTL_TIMEOUT ?= 300s CERT_MANAGER_TIMEOUT ?= 120s