diff --git a/.gitignore b/.gitignore index 542d9e96..dec821c0 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,7 @@ specs main # E2E test reports -.e2e-reports/ \ No newline at end of file +.e2e-reports/ + +# Generated files +scripts/ldap/configmap.yaml \ No newline at end of file diff --git a/Makefile b/Makefile index 837354e1..7804c4ba 100644 --- a/Makefile +++ b/Makefile @@ -1,45 +1,75 @@ -# Image URL to use all building/pushing image targets -REV=$(shell git rev-parse --short HEAD) -TAG ?= $(REV) +# ============================================================================== +# Git Information +# ============================================================================== -IMG_WITHOUT_TAG ?= $(REGISTRY)/envoy-xds-controller -UI_IMG_WITHOUT_TAG ?= $(REGISTRY)/envoy-xds-controller-ui -INIT_CERT_IMG_WITHOUT_TAG ?= $(REGISTRY)/envoy-xds-controller-init-cert +GIT_COMMIT := $(shell git rev-parse --short HEAD) -IMG ?= $(IMG_WITHOUT_TAG):$(TAG) -UI_IMG ?= $(UI_IMG_WITHOUT_TAG):$(TAG) -INIT_CERT_IMG ?= $(INIT_CERT_IMG_WITHOUT_TAG):$(TAG) +# ============================================================================== +# Container Images +# ============================================================================== -DEPLOY_TIMEOUT ?= 5m +# Image registries +REGISTRY ?= docker.io/kaasops +LOCAL_REGISTRY ?= localhost:5001 -PROM_OPERATOR_VERSION ?= v0.77.1 +# Image tag (defaults to git commit) +IMAGE_TAG ?= $(GIT_COMMIT) -# REGISTRY is the image registry to use for build and push image targets. -REGISTRY ?= docker.io/kaasops +# Image repositories +IMG_REPO ?= $(REGISTRY)/envoy-xds-controller +UI_IMG_REPO ?= $(REGISTRY)/envoy-xds-controller-ui +INIT_CERT_IMG_REPO ?= $(REGISTRY)/envoy-xds-controller-init-cert -# LOCAL_REGISTRY is the local image registry to use for build and push image targets. -LOCAL_REGISTRY ?= localhost:5001 +# Full image references +IMG ?= $(IMG_REPO):$(IMAGE_TAG) +UI_IMG ?= $(UI_IMG_REPO):$(IMAGE_TAG) +INIT_CERT_IMG ?= $(INIT_CERT_IMG_REPO):$(IMAGE_TAG) -# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.31.0 +# Container runtime (docker or podman) +CONTAINER_TOOL ?= docker + +# ============================================================================== +# Versions +# ============================================================================== + +PROM_OPERATOR_VERSION ?= v0.77.1 +KUSTOMIZE_VERSION ?= v5.5.0 +CONTROLLER_TOOLS_VERSION ?= v0.16.4 +ENVTEST_VERSION ?= release-0.19 +ENVTEST_K8S_VERSION ?= 1.31.0 +GOLANGCI_LINT_VERSION ?= v1.64.8 + +# ============================================================================== +# Deployment +# ============================================================================== + +DEPLOY_TIMEOUT ?= 5m +HELM_REPO_URL ?= https://kaasops.github.io/envoy-xds-controller/helm + +# ============================================================================== +# Build Tools +# ============================================================================== + +LOCALBIN ?= $(shell pwd)/bin +KUBECTL ?= kubectl +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest +GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +# Go binary path ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin +GOBIN := $(shell go env GOPATH)/bin else -GOBIN=$(shell go env GOBIN) +GOBIN := $(shell go env GOBIN) endif -# CONTAINER_TOOL defines the container tool to be used for building images. -# Be aware that the target commands are only tested with Docker which is -# scaffolded by default. However, you might want to replace it to use other -# tools. (i.e. podman) -CONTAINER_TOOL ?= docker +# ============================================================================== +# Shell Configuration +# ============================================================================== -# Setting SHELL to bash allows bash commands to be executed by recipes. -# Options are set to exit when a recipe line exits non-zero or a piped command fails. -SHELL = /usr/bin/env bash -o pipefail -.SHELLFLAGS = -ec +SHELL := /usr/bin/env bash -o pipefail +.SHELLFLAGS := -ec .DEFAULT_GOAL := help @@ -65,8 +95,8 @@ help: ## Display this help. .PHONY: version version: ## Show version information - @echo "Tag: $(TAG)" - @echo "Revision: $(REV)" + @echo "Tag: $(IMAGE_TAG)" + @echo "Commit: $(GIT_COMMIT)" @echo "Registry: $(REGISTRY)" @echo "Main Image: $(IMG)" @echo "UI Image: $(UI_IMG)" @@ -146,7 +176,7 @@ test-e2e-report: manifests generate fmt vet ## Run the e2e tests with report sav @REPORT_FILE="$(E2E_REPORTS_DIR)/e2e-test-$$(date +%Y%m%d-%H%M%S).log"; \ echo "Running e2e tests with report saved to $$REPORT_FILE"; \ go test ./test/e2e/ -v -ginkgo.v -timeout 15m -ginkgo.no-color 2>&1 | tee $$REPORT_FILE; \ - TEST_EXIT_CODE=$${PIPEFAIL[0]}; \ + TEST_EXIT_CODE=$${PIPESTATUS[0]}; \ echo ""; \ echo "Report saved to: $$REPORT_FILE"; \ exit $$TEST_EXIT_CODE @@ -164,8 +194,8 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes .PHONY: build build: manifests generate fmt vet ## Build manager binary. go build -o bin/manager \ - -ldflags "-X github.com/kaasops/envoy-xds-controller/internal/buildinfo.Version=$(TAG) \ - -X github.com/kaasops/envoy-xds-controller/internal/buildinfo.CommitHash=$(REV) \ + -ldflags "-X github.com/kaasops/envoy-xds-controller/internal/buildinfo.Version=$(IMAGE_TAG) \ + -X github.com/kaasops/envoy-xds-controller/internal/buildinfo.CommitHash=$(GIT_COMMIT) \ -X github.com/kaasops/envoy-xds-controller/internal/buildinfo.BuildDate=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")" \ cmd/main.go @@ -183,8 +213,8 @@ run: manifests generate fmt vet ## Run a controller from your host. .PHONY: docker-build docker-build: ## Build docker image with the manager. $(CONTAINER_TOOL) build \ - --build-arg VERSION=$(TAG) \ - --build-arg COMMIT_HASH=$(REV) \ + --build-arg VERSION=$(IMAGE_TAG) \ + --build-arg COMMIT_HASH=$(GIT_COMMIT) \ --build-arg BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ") \ -t ${IMG} . @@ -197,10 +227,7 @@ docker-build-init-cert: ## Build docker image with the init-cert. $(CONTAINER_TOOL) build -t ${INIT_CERT_IMG} -f cmd/init-cert/Dockerfile . .PHONY: docker-build-all -docker-build-all: docker-build docker-build-ui docker-build-init-cert - -.PHONY: docker-build-all-local -docker-build-all-local: set-local docker-build-all +docker-build-all: docker-build docker-build-ui docker-build-init-cert ## Build all docker images .PHONY: docker-cache-clear docker-cache-clear: ## Clear Docker build cache @@ -232,10 +259,7 @@ docker-push-init-cert: ## Push docker image with the init-cert $(CONTAINER_TOOL) push ${INIT_CERT_IMG} .PHONY: docker-push-all -docker-push-all: docker-push docker-push-ui docker-push-init-cert - -.PHONY: docker-push-all-local -docker-push-all-local: set-local docker-push-all +docker-push-all: docker-push docker-push-ui docker-push-init-cert ## Push all docker images # PLATFORMS defines the target platforms for the manager image be built to provide support to multiple # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: @@ -285,24 +309,9 @@ undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/. ##@ Dependencies -## Location to install dependencies to -LOCALBIN ?= $(shell pwd)/bin $(LOCALBIN): mkdir -p $(LOCALBIN) -## Tool Binaries -KUBECTL ?= kubectl -KUSTOMIZE ?= $(LOCALBIN)/kustomize -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -ENVTEST ?= $(LOCALBIN)/setup-envtest -GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint - -## Tool Versions -KUSTOMIZE_VERSION ?= v5.5.0 -CONTROLLER_TOOLS_VERSION ?= v0.16.4 -ENVTEST_VERSION ?= release-0.19 -GOLANGCI_LINT_VERSION ?= v1.64.8 - .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. $(KUSTOMIZE): $(LOCALBIN) @@ -339,142 +348,106 @@ mv $(1) $(1)-$(3) ;\ ln -sf $(1)-$(3) $(1) endef -## HELM - -URL=https://kaasops.github.io/envoy-xds-controller/helm -AUTH_ENABLED=false +##@ Helm .PHONY: helm-lint -helm-lint: +helm-lint: ## Lint Helm chart helm lint helm/charts/envoy-xds-controller .PHONY: helm-package -helm-package: +helm-package: ## Package Helm chart helm package helm/charts/* -d helm/packages .PHONY: helm-index -helm-index: - helm repo index --url ${URL} ./helm +helm-index: ## Update Helm repo index + helm repo index --url $(HELM_REPO_URL) ./helm + +.PHONY: helm-template +helm-template: ## Render Helm chart templates locally + helm template exc -n envoy-xds-controller ./helm/charts/envoy-xds-controller/ -### HELM DEPLOY +##@ Local Development -.PHONY: helm-deploy-local -helm-deploy-local: manifests set-local ## Install Envoy xDS Controller into the local Kubernetes cluster specified in ~/.kube/config. - @$(LOG_TARGET) - helm install exc --set metrics.address=:8443 \ - --set metrics.secure=false \ - --set development=true \ - --set auth.enabled=$(AUTH_ENABLED) \ - --set 'watchNamespaces={default}' \ - --set image.repository=$(IMG_WITHOUT_TAG) \ - --set image.tag=$(TAG) \ - --set ui.enabled=true \ - --set cacheAPI.enabled=true \ - --set ui.image.repository=$(UI_IMG_WITHOUT_TAG) \ - --set ui.image.tag=$(TAG) \ - --set initCert.image.repository=$(INIT_CERT_IMG_WITHOUT_TAG) \ - --set initCert.image.tag=$(TAG) \ - --set resourceAPI.enabled=true \ - --namespace envoy-xds-controller \ - --create-namespace ./helm/charts/envoy-xds-controller \ - --debug --timeout='$(DEPLOY_TIMEOUT)' --wait - -.PHONY: set-local -set-local: - $(eval REGISTRY := $(LOCAL_REGISTRY)) - -.PHONY: set-auth-env -set-auth-env: - $(eval AUTH_ENABLED := true) - -.PHONY: debug-local -debug-local: set-local - @echo $(REGISTRY) - @echo $(IMG) - -.PHONY: dev-local -dev-local: set-local docker-build-all docker-push-all helm-deploy-local +.PHONY: dev +dev: ## Interactive local development setup in Kind + @bash scripts/dev.sh + +.PHONY: dev-update +dev-update: ## Rebuild and redeploy to existing dev cluster + @bash scripts/dev-update.sh + +.PHONY: dev-clean +dev-clean: ## Remove Helm release from Kind cluster + helm uninstall exc -n envoy-xds-controller || true .PHONY: kr -kr: +kr: ## Create Kind cluster with local registry bash scripts/kind-with-registry.sh .PHONY: kd -kd: +kd: ## Delete Kind cluster kind delete cluster .PHONY: dev-apply-resources -dev-apply-resources: +dev-apply-resources: ## Apply test resources to cluster kubectl -n envoy-xds-controller apply -f dev/testdata/common .PHONY: dev-delete-resources -dev-delete-resources: - kubectl -n envoy-xds-controller delete -f dev/testdata - -.PHONY: helm-deploy-backend-local -helm-deploy-backend-local: manifests set-local ## Install Envoy xDS Controller into the local Kubernetes cluster specified in ~/.kube/config. - @$(LOG_TARGET) - helm install exc --set metrics.address=:8443 \ - --set 'watchNamespaces={default}' \ - --set image.repository=$(IMG_WITHOUT_TAG) \ - --set image.tag=$(TAG) \ - --set initCert.image.repository=$(INIT_CERT_IMG_WITHOUT_TAG) \ - --set initCert.image.tag=$(TAG) \ - --set cacheAPI.enabled=true \ - --set resourceAPI.enabled=true \ - --namespace envoy-xds-controller \ - --create-namespace ./helm/charts/envoy-xds-controller \ - --debug --timeout='$(DEPLOY_TIMEOUT)' --wait - -.PHONY: dev-backend -dev-backend: set-local docker-build docker-push docker-build-init-cert docker-push-init-cert install-prometheus helm-deploy-backend-local +dev-delete-resources: ## Delete test resources from cluster + kubectl -n envoy-xds-controller delete -f dev/testdata/common -.PHONY: deploy-e2e -deploy-e2e: manifests - helm install exc-e2e --set metrics.address=:8443 \ - --set 'watchNamespaces={default,exc-secrets-ns1,exc-secrets-ns2}' \ - --set image.repository=$(IMG_WITHOUT_TAG) \ - --set image.tag=$(TAG) \ - --set initCert.image.repository=$(INIT_CERT_IMG_WITHOUT_TAG) \ - --set initCert.image.tag=$(TAG) \ - --set cacheAPI.enabled=true \ - --set resourceAPI.enabled=true \ - --set development=true \ - --namespace envoy-xds-controller \ - --create-namespace ./helm/charts/envoy-xds-controller \ - --debug --timeout='$(DEPLOY_TIMEOUT)' --wait +.PHONY: dev-auth +dev-auth: ## Setup Dex + LDAP for authentication testing + bash scripts/dev-auth.sh -.PHONY: undeploy-e2e -undeploy-e2e: - helm uninstall -n envoy-xds-controller exc-e2e +.PHONY: dev-creds +dev-creds: ## Show test credentials for auth + @bash scripts/dev-creds.sh + +.PHONY: dev-auth-generate +dev-auth-generate: ## Regenerate LDAP config from users.yaml + @bash scripts/ldap/generate.sh + +.PHONY: dev-envoy +dev-envoy: ## Deploy test Envoy instance + kubectl apply -f dev/envoy + +.PHONY: dev-frontend +dev-frontend: ## Run UI development server (npm run dev) + cd ui && npm run dev .PHONY: install-prometheus -install-prometheus: +install-prometheus: ## Install Prometheus Operator kubectl create -f https://github.com/prometheus-operator/prometheus-operator/releases/download/$(PROM_OPERATOR_VERSION)/bundle.yaml .PHONY: uninstall-prometheus -uninstall-prometheus: +uninstall-prometheus: ## Uninstall Prometheus Operator kubectl delete -f https://github.com/prometheus-operator/prometheus-operator/releases/download/$(PROM_OPERATOR_VERSION)/bundle.yaml -.PHONY: bufgen -bufgen: - buf generate - -.PHONY: dev-auth -dev-auth: - bash scripts/dev-auth.sh +##@ E2E Testing -.PHONY: dev-local-with-auth -dev-local-with-auth: dev-auth set-auth-env install-prometheus dev-local +.PHONY: deploy-e2e +deploy-e2e: manifests ## Deploy controller for e2e tests + helm install exc-e2e \ + --set metrics.address=:8443 \ + --set 'watchNamespaces={default,exc-secrets-ns1,exc-secrets-ns2}' \ + --set image.repository=$(IMG_REPO) \ + --set image.tag=$(IMAGE_TAG) \ + --set initCert.image.repository=$(INIT_CERT_IMG_REPO) \ + --set initCert.image.tag=$(IMAGE_TAG) \ + --set cacheAPI.enabled=true \ + --set resourceAPI.enabled=true \ + --set development=true \ + --namespace envoy-xds-controller \ + --create-namespace ./helm/charts/envoy-xds-controller \ + --debug --timeout='$(DEPLOY_TIMEOUT)' --wait -.PHONY: helm-template -helm-template: - helm template exc -n envoy-xds-controller ./helm/charts/envoy-xds-controller/ +.PHONY: undeploy-e2e +undeploy-e2e: ## Remove e2e test deployment + helm uninstall -n envoy-xds-controller exc-e2e -.PHONY: dev-envoy -dev-envoy: - kubectl apply -f dev/envoy +##@ Code Generation -.PHONY: dev-frontend -dev-frontend: - cd ui && npm run dev \ No newline at end of file +.PHONY: bufgen +bufgen: ## Generate protobuf code + buf generate \ No newline at end of file diff --git a/helm/charts/envoy-xds-controller/templates/metrics/servicemonitor.yaml b/helm/charts/envoy-xds-controller/templates/metrics/servicemonitor.yaml index 2256f002..b7165545 100644 --- a/helm/charts/envoy-xds-controller/templates/metrics/servicemonitor.yaml +++ b/helm/charts/envoy-xds-controller/templates/metrics/servicemonitor.yaml @@ -1,4 +1,4 @@ -{{- if ne .Values.metrics.address "0" }} +{{- if and (ne .Values.metrics.address "0") .Values.metrics.serviceMonitor.enabled }} # Prometheus Monitor Service (Metrics) apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor diff --git a/helm/charts/envoy-xds-controller/values.yaml b/helm/charts/envoy-xds-controller/values.yaml index eaed03ec..5d175714 100644 --- a/helm/charts/envoy-xds-controller/values.yaml +++ b/helm/charts/envoy-xds-controller/values.yaml @@ -7,6 +7,8 @@ development: false metrics: address: "0" # set "0" for disabling secure: true + serviceMonitor: + enabled: false # requires Prometheus Operator CRDs xds: port: 9000 @@ -238,7 +240,7 @@ auth: nodeIdsByGroup: admins: - "*" - authors: + editors: - "node1" users: - "node1" diff --git a/scripts/dev-auth.sh b/scripts/dev-auth.sh index ae97f3d2..15823495 100644 --- a/scripts/dev-auth.sh +++ b/scripts/dev-auth.sh @@ -2,8 +2,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -kubectl create ns ldap -kubectl create ns dex +# Generate LDAP config from dev-users.yaml +bash "${SCRIPT_DIR}/ldap/generate.sh" + +kubectl create ns ldap --dry-run=client -o yaml | kubectl apply -f - +kubectl create ns dex --dry-run=client -o yaml | kubectl apply -f - kubectl apply -f "${SCRIPT_DIR}/ldap" -n ldap diff --git a/scripts/dev-creds.sh b/scripts/dev-creds.sh new file mode 100755 index 00000000..c90db4ab --- /dev/null +++ b/scripts/dev-creds.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Shows test credentials from dev-users.yaml + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +USERS_FILE="${SCRIPT_DIR}/dev-users.yaml" + +# Colors +CYAN='\033[0;36m' +GRAY='\033[0;90m' +NC='\033[0m' + +if [[ ! -f "$USERS_FILE" ]]; then + echo "Error: $USERS_FILE not found" + exit 1 +fi + +echo "" +echo -e "${CYAN}LDAP Users${NC}" +echo -e "${GRAY}───────────────────────────────────────────────────────────────${NC}" +printf " %-26s %-14s %s\n" "EMAIL" "PASSWORD" "GROUPS" +echo -e "${GRAY}───────────────────────────────────────────────────────────────${NC}" + +in_ldap=false +in_dex=false + +while IFS= read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^ldap_users: ]] && { in_ldap=true; in_dex=false; continue; } + [[ "$line" =~ ^dex_users: ]] && { + in_ldap=false + in_dex=true + echo "" + echo -e "${CYAN}Dex Static Users${NC}" + echo -e "${GRAY}───────────────────────────────────────────────────────────────${NC}" + printf " %-26s %s\n" "EMAIL" "PASSWORD" + echo -e "${GRAY}───────────────────────────────────────────────────────────────${NC}" + continue + } + + if $in_ldap; then + [[ "$line" =~ email:[[:space:]]*(.+) ]] && email="${BASH_REMATCH[1]}" + [[ "$line" =~ password:[[:space:]]*(.+) ]] && password="${BASH_REMATCH[1]}" + [[ "$line" =~ groups:[[:space:]]*(.+) ]] && { + groups="${BASH_REMATCH[1]}" + printf " %-26s %-14s %s\n" "$email" "$password" "$groups" + } + fi + + if $in_dex; then + [[ "$line" =~ email:[[:space:]]*(.+) ]] && email="${BASH_REMATCH[1]}" + [[ "$line" =~ password:[[:space:]]*(.+) ]] && { + password="${BASH_REMATCH[1]}" + printf " %-26s %s\n" "$email" "$password" + } + fi +done < "$USERS_FILE" + +echo "" diff --git a/scripts/dev-update.sh b/scripts/dev-update.sh new file mode 100755 index 00000000..9606624b --- /dev/null +++ b/scripts/dev-update.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# Rebuild and redeploy to existing dev cluster + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Image settings +LOCAL_REGISTRY="${LOCAL_REGISTRY:-localhost:5001}" +GIT_COMMIT=$(git rev-parse --short HEAD) +IMAGE_TAG="${IMAGE_TAG:-$GIT_COMMIT}" + +IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller" +UI_IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller-ui" +INIT_CERT_IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller-init-cert" + +echo -e "${BLUE}============================================${NC}" +echo -e "${BLUE} Updating dev deployment (${IMAGE_TAG})${NC}" +echo -e "${BLUE}============================================${NC}" +echo "" + +# Check if release exists +if ! helm status exc -n envoy-xds-controller &>/dev/null; then + echo -e "${RED}Error: No existing deployment found.${NC}" + echo -e "Run ${GREEN}make dev${NC} first to create initial deployment." + exit 1 +fi + +# Get current values +UI_ENABLED=$(helm get values exc -n envoy-xds-controller -o json 2>/dev/null | grep -o '"ui":{"enabled":[^,}]*' | grep -o 'true\|false' || echo "true") + +# Build images +echo -e "${BLUE}Building controller image...${NC}" +docker build \ + --build-arg VERSION="$IMAGE_TAG" \ + --build-arg COMMIT_HASH="$GIT_COMMIT" \ + --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + -t "${IMG_REPO}:${IMAGE_TAG}" "$ROOT_DIR" +docker push "${IMG_REPO}:${IMAGE_TAG}" + +echo -e "${BLUE}Building init-cert image...${NC}" +docker build -t "${INIT_CERT_IMG_REPO}:${IMAGE_TAG}" -f "$ROOT_DIR/cmd/init-cert/Dockerfile" "$ROOT_DIR" +docker push "${INIT_CERT_IMG_REPO}:${IMAGE_TAG}" + +if [ "$UI_ENABLED" = "true" ]; then + echo -e "${BLUE}Building UI image...${NC}" + docker build -t "${UI_IMG_REPO}:${IMAGE_TAG}" -f "$ROOT_DIR/ui/Dockerfile" "$ROOT_DIR/ui" + docker push "${UI_IMG_REPO}:${IMAGE_TAG}" +fi + +# Upgrade release +echo -e "${BLUE}Upgrading Helm release...${NC}" +helm upgrade exc \ + --reuse-values \ + --set image.repository="$IMG_REPO" \ + --set image.tag="$IMAGE_TAG" \ + --set ui.image.repository="$UI_IMG_REPO" \ + --set ui.image.tag="$IMAGE_TAG" \ + --set initCert.image.repository="$INIT_CERT_IMG_REPO" \ + --set initCert.image.tag="$IMAGE_TAG" \ + --namespace envoy-xds-controller \ + "$ROOT_DIR/helm/charts/envoy-xds-controller" \ + --timeout='5m' --wait + +echo "" +echo -e "${GREEN}============================================${NC}" +echo -e "${GREEN} Update complete!${NC}" +echo -e "${GREEN}============================================${NC}" diff --git a/scripts/dev-users.yaml b/scripts/dev-users.yaml new file mode 100644 index 00000000..42598975 --- /dev/null +++ b/scripts/dev-users.yaml @@ -0,0 +1,38 @@ +# Test users for local development +# Source of truth for LDAP and Dex credentials +# Run 'make dev-auth-generate' after changes to regenerate LDAP config + +ldap_users: + - cn: admin + email: admin@example.com + password: admin + groups: admins + + - cn: developer + email: developer@example.com + password: developer + groups: developers + + - cn: editor + email: editor@example.com + password: editor + groups: editors + + - cn: tester + email: tester@example.com + password: tester + groups: testers + + - cn: user + email: user@example.com + password: user + groups: users + + - cn: devops + email: devops@example.com + password: devops + groups: admins, developers + +dex_users: + - email: sa@example.com + password: password diff --git a/scripts/dev.sh b/scripts/dev.sh new file mode 100755 index 00000000..8818fdd1 --- /dev/null +++ b/scripts/dev.sh @@ -0,0 +1,170 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Image settings (match Makefile variable names) +LOCAL_REGISTRY="${LOCAL_REGISTRY:-localhost:5001}" +GIT_COMMIT=$(git rev-parse --short HEAD) +IMAGE_TAG="${IMAGE_TAG:-$GIT_COMMIT}" + +IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller" +UI_IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller-ui" +INIT_CERT_IMG_REPO="${LOCAL_REGISTRY}/envoy-xds-controller-init-cert" + +# Defaults +UI_ENABLED=true +AUTH_ENABLED=false +PROMETHEUS_ENABLED=false +DEV_MODE=true +DEPLOY_ENVOY=false +APPLY_TEST_RESOURCES=false + +# Banner +echo -e "${BLUE}============================================${NC}" +echo -e "${BLUE} Envoy xDS Controller - Dev Setup${NC}" +echo -e "${BLUE}============================================${NC}" +echo "" + +# Check Kind cluster +if ! kind get clusters 2>/dev/null | grep -q 'kind'; then + echo -e "${RED}Error: No Kind cluster found.${NC}" + echo -e "Run ${YELLOW}make kr${NC} first to create cluster with registry." + exit 1 +fi + +echo -e "${GREEN}Kind cluster found.${NC}" +echo "" + +# Interactive prompts +echo "Select options for local development:" +echo "" + +read -p "Enable UI? [Y/n]: " ui_choice +[[ "$ui_choice" =~ ^[Nn]$ ]] && UI_ENABLED=false + +read -p "Enable Auth (OIDC via Dex)? [y/N]: " auth_choice +[[ "$auth_choice" =~ ^[Yy]$ ]] && AUTH_ENABLED=true + +read -p "Install Prometheus Operator? [y/N]: " prom_choice +[[ "$prom_choice" =~ ^[Yy]$ ]] && PROMETHEUS_ENABLED=true + +read -p "Development mode (verbose logging)? [Y/n]: " dev_choice +[[ "$dev_choice" =~ ^[Nn]$ ]] && DEV_MODE=false + +read -p "Deploy test Envoy proxy? [y/N]: " envoy_choice +[[ "$envoy_choice" =~ ^[Yy]$ ]] && DEPLOY_ENVOY=true + +read -p "Apply test resources (VirtualServices, etc.)? [y/N]: " resources_choice +[[ "$resources_choice" =~ ^[Yy]$ ]] && APPLY_TEST_RESOURCES=true + +echo "" +echo -e "${YELLOW}Configuration:${NC}" +echo " UI: $UI_ENABLED" +echo " Auth: $AUTH_ENABLED" +echo " Prometheus: $PROMETHEUS_ENABLED" +echo " Dev mode: $DEV_MODE" +echo " Deploy Envoy: $DEPLOY_ENVOY" +echo " Test resources: $APPLY_TEST_RESOURCES" +echo "" + +# Auth setup (if enabled) +if [ "$AUTH_ENABLED" = true ]; then + echo -e "${BLUE}Setting up Auth (Dex + LDAP)...${NC}" + bash "${SCRIPT_DIR}/dev-auth.sh" +fi + +# Prometheus setup (if enabled) +if [ "$PROMETHEUS_ENABLED" = true ]; then + echo -e "${BLUE}Installing Prometheus Operator...${NC}" + make -C "$ROOT_DIR" install-prometheus +fi + +# Build images +echo -e "${BLUE}Building controller image...${NC}" +docker build \ + --build-arg VERSION="$IMAGE_TAG" \ + --build-arg COMMIT_HASH="$GIT_COMMIT" \ + --build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + -t "${IMG_REPO}:${IMAGE_TAG}" "$ROOT_DIR" +docker push "${IMG_REPO}:${IMAGE_TAG}" + +echo -e "${BLUE}Building init-cert image...${NC}" +docker build -t "${INIT_CERT_IMG_REPO}:${IMAGE_TAG}" -f "$ROOT_DIR/cmd/init-cert/Dockerfile" "$ROOT_DIR" +docker push "${INIT_CERT_IMG_REPO}:${IMAGE_TAG}" + +if [ "$UI_ENABLED" = true ]; then + echo -e "${BLUE}Building UI image...${NC}" + docker build -t "${UI_IMG_REPO}:${IMAGE_TAG}" -f "$ROOT_DIR/ui/Dockerfile" "$ROOT_DIR/ui" + docker push "${UI_IMG_REPO}:${IMAGE_TAG}" +fi + +# Uninstall existing release if present +echo -e "${BLUE}Removing existing Helm release (if any)...${NC}" +helm uninstall exc -n envoy-xds-controller 2>/dev/null || true + +# Deploy via Helm +echo -e "${BLUE}Deploying with Helm...${NC}" +helm install exc \ + --set metrics.address=:8443 \ + --set metrics.secure=false \ + --set metrics.serviceMonitor.enabled="$PROMETHEUS_ENABLED" \ + --set development="$DEV_MODE" \ + --set auth.enabled="$AUTH_ENABLED" \ + --set ui.enabled="$UI_ENABLED" \ + --set cacheAPI.enabled=true \ + --set resourceAPI.enabled=true \ + --set 'watchNamespaces={default}' \ + --set image.repository="$IMG_REPO" \ + --set image.tag="$IMAGE_TAG" \ + --set ui.image.repository="$UI_IMG_REPO" \ + --set ui.image.tag="$IMAGE_TAG" \ + --set initCert.image.repository="$INIT_CERT_IMG_REPO" \ + --set initCert.image.tag="$IMAGE_TAG" \ + --namespace envoy-xds-controller \ + --create-namespace "$ROOT_DIR/helm/charts/envoy-xds-controller" \ + --timeout='5m' --wait + +# Deploy Envoy (if enabled) +if [ "$DEPLOY_ENVOY" = true ]; then + echo -e "${BLUE}Deploying test Envoy proxy...${NC}" + kubectl apply -f "$ROOT_DIR/dev/envoy" +fi + +# Apply test resources (if enabled) +if [ "$APPLY_TEST_RESOURCES" = true ]; then + echo -e "${BLUE}Applying test resources...${NC}" + kubectl -n envoy-xds-controller apply -f "$ROOT_DIR/dev/testdata/common" +fi + +echo "" +echo -e "${GREEN}============================================${NC}" +echo -e "${GREEN} Deployment complete!${NC}" +echo -e "${GREEN}============================================${NC}" +echo "" +echo "Useful commands:" +echo " kubectl -n envoy-xds-controller get pods" +echo " kubectl -n envoy-xds-controller logs -f deployment/exc-envoy-xds-controller" +if [ "$UI_ENABLED" = true ]; then + echo " kubectl -n envoy-xds-controller port-forward svc/exc-envoy-xds-controller-ui 8080:8080" +fi +if [ "$DEPLOY_ENVOY" = true ]; then + echo " kubectl -n default logs -f deployment/envoy" + echo " kubectl -n default port-forward svc/envoy 10000:10000" +fi +if [ "$APPLY_TEST_RESOURCES" = true ]; then + echo " kubectl -n envoy-xds-controller get virtualservices" +fi + +# Show test credentials if auth is enabled +if [ "$AUTH_ENABLED" = true ]; then + bash "${SCRIPT_DIR}/dev-creds.sh" +fi diff --git a/scripts/ldap/configmap.yaml b/scripts/ldap/configmap.yaml deleted file mode 100644 index fc2b0cfd..00000000 --- a/scripts/ldap/configmap.yaml +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: ldap-configmap - labels: - app: ldap -data: - config-ldap.ldif: |- - # dn: dc=example,dc=org - # objectClass: dcObject - # objectClass: organization - # o: Example Company - # dc: example - - dn: ou=People,dc=example,dc=org - objectClass: organizationalUnit - ou: People - - dn: cn=jane,ou=People,dc=example,dc=org - objectClass: person - objectClass: inetOrgPerson - sn: doe - cn: jane - mail: janedoe@example.com - userpassword: foo - - dn: cn=john,ou=People,dc=example,dc=org - objectClass: person - objectClass: inetOrgPerson - sn: doe - cn: john - mail: johndoe@example.com - userpassword: bar - - dn: cn=tester,ou=People,dc=example,dc=org - objectClass: person - objectClass: inetOrgPerson - sn: tester - cn: tester - mail: tester@example.com - userpassword: tester - - dn: cn=user,ou=People,dc=example,dc=org - objectClass: person - objectClass: inetOrgPerson - sn: user - cn: user - mail: user@example.com - userpassword: user - - # Group definitions. - - dn: ou=Groups,dc=example,dc=org - objectClass: organizationalUnit - ou: Groups - - dn: cn=admins,ou=Groups,dc=example,dc=org - objectClass: groupOfNames - cn: admins - member: cn=john,ou=People,dc=example,dc=org - - dn: cn=developers,ou=Groups,dc=example,dc=org - objectClass: groupOfNames - cn: developers - member: cn=jane,ou=People,dc=example,dc=org - - dn: cn=testers,ou=Groups,dc=example,dc=org - objectClass: groupOfNames - cn: testers - member: cn=tester,ou=People,dc=example,dc=org - - dn: cn=users,ou=Groups,dc=example,dc=org - objectClass: groupOfNames - cn: users - member: cn=user,ou=People,dc=example,dc=org \ No newline at end of file diff --git a/scripts/ldap/generate.sh b/scripts/ldap/generate.sh new file mode 100755 index 00000000..a8a045d5 --- /dev/null +++ b/scripts/ldap/generate.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Generates LDAP configmap.yaml from dev-users.yaml + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +USERS_FILE="${SCRIPT_DIR}/../dev-users.yaml" +OUTPUT_FILE="${SCRIPT_DIR}/configmap.yaml" + +if [[ ! -f "$USERS_FILE" ]]; then + echo "Error: dev-users.yaml not found" + exit 1 +fi + +# Temp files for collecting data +TMP_USERS=$(mktemp) +TMP_GROUPS=$(mktemp) +trap "rm -f $TMP_USERS $TMP_GROUPS" EXIT + +# Parse users.yaml +in_ldap=false +while IFS= read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^ldap_users: ]] && { in_ldap=true; continue; } + [[ "$line" =~ ^dex_users: ]] && { in_ldap=false; continue; } + + if $in_ldap; then + [[ "$line" =~ ^[[:space:]]*-[[:space:]]*cn:[[:space:]]*(.+) ]] && cn="${BASH_REMATCH[1]}" + [[ "$line" =~ ^[[:space:]]*email:[[:space:]]*(.+) ]] && email="${BASH_REMATCH[1]}" + [[ "$line" =~ ^[[:space:]]*password:[[:space:]]*(.+) ]] && password="${BASH_REMATCH[1]}" + [[ "$line" =~ ^[[:space:]]*groups:[[:space:]]*(.+) ]] && { + groups="${BASH_REMATCH[1]}" + echo "${cn}|${email}|${password}|${groups}" >> "$TMP_USERS" + } + fi +done < "$USERS_FILE" + +# Generate configmap +cat > "$OUTPUT_FILE" << 'HEADER' +# Auto-generated from dev-users.yaml - do not edit manually +# Run: make dev-auth-generate +apiVersion: v1 +kind: ConfigMap +metadata: + name: ldap-configmap + labels: + app: ldap +data: + config-ldap.ldif: |- + dn: ou=People,dc=example,dc=org + objectClass: organizationalUnit + ou: People + +HEADER + +# Generate user entries +while IFS='|' read -r cn email password groups; do + cat >> "$OUTPUT_FILE" << EOF + dn: cn=${cn},ou=People,dc=example,dc=org + objectClass: person + objectClass: inetOrgPerson + sn: ${cn} + cn: ${cn} + mail: ${email} + userpassword: ${password} + +EOF + # Add each group for this user (supports comma-separated groups) + IFS=',' read -ra group_list <<< "$groups" + for group in "${group_list[@]}"; do + group=$(echo "$group" | xargs) # trim whitespace + echo "${group}|${cn}" >> "$TMP_GROUPS" + done +done < "$TMP_USERS" + +# Generate groups section +cat >> "$OUTPUT_FILE" << 'GROUPS_HEADER' + # Group definitions + dn: ou=Groups,dc=example,dc=org + objectClass: organizationalUnit + ou: Groups + +GROUPS_HEADER + +# Get unique groups and generate entries +cut -d'|' -f1 "$TMP_GROUPS" | sort -u | while read -r group; do + cat >> "$OUTPUT_FILE" << EOF + dn: cn=${group},ou=Groups,dc=example,dc=org + objectClass: groupOfNames + cn: ${group} +EOF + # Add members for this group + grep "^${group}|" "$TMP_GROUPS" | cut -d'|' -f2 | while read -r cn; do + echo " member: cn=${cn},ou=People,dc=example,dc=org" >> "$OUTPUT_FILE" + done + echo "" >> "$OUTPUT_FILE" +done + +echo "Generated: $OUTPUT_FILE" diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 64c1e2cf..8e1c49a5 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -65,10 +65,9 @@ var _ = Describe("Manager", Ordered, func() { By("deploying the controller-manager") cmd = exec.Command( "make", "deploy-e2e", - fmt.Sprintf("IMG_WITHOUT_TAG=%s", projectImage), - fmt.Sprintf("TAG=%s", projectImageTag), - fmt.Sprintf("INIT_CERT_IMG_WITHOUT_TAG=%s", initCertImage), - fmt.Sprintf("TAG=%s", projectImageTag), + fmt.Sprintf("IMG_REPO=%s", projectImage), + fmt.Sprintf("IMAGE_TAG=%s", projectImageTag), + fmt.Sprintf("INIT_CERT_IMG_REPO=%s", initCertImage), ) _, err = utils.Run(cmd) Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager")