Kubernetes Operator for Tangled Spindles
15
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 441 lines 19 kB view raw
1# VERSION defines the project version for the bundle. 2# Update this value when you upgrade the version of your project. 3# To re-generate a bundle for another specific version without changing the standard setup, you can: 4# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) 5# - use environment variables to overwrite this value (e.g export VERSION=0.0.2) 6VERSION ?= 0.1.5 7 8# CHANNELS define the bundle channels used in the bundle. 9# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") 10# To re-generate a bundle for other specific channels without changing the standard setup, you can: 11# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable) 12# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable") 13ifneq ($(origin CHANNELS), undefined) 14BUNDLE_CHANNELS := --channels=$(CHANNELS) 15endif 16 17# DEFAULT_CHANNEL defines the default channel used in the bundle. 18# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable") 19# To re-generate a bundle for any other default channel without changing the default setup, you can: 20# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) 21# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") 22ifneq ($(origin DEFAULT_CHANNEL), undefined) 23BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) 24endif 25BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) 26 27# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. 28# This variable is used to construct full image tags for bundle and catalog images. 29# 30# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both 31# j5t.io/loom-bundle:$VERSION and j5t.io/loom-catalog:$VERSION. 32IMAGE_TAG_BASE ?= j5t.io/loom 33 34# BUNDLE_IMG defines the image:tag used for the bundle. 35# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>) 36BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) 37 38# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command 39BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) 40 41# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests 42# You can enable this value if you would like to use SHA Based Digests 43# To enable set flag to true 44USE_IMAGE_DIGESTS ?= false 45ifeq ($(USE_IMAGE_DIGESTS), true) 46 BUNDLE_GEN_FLAGS += --use-image-digests 47endif 48 49# Set the Operator SDK version to use. By default, what is installed on the system is used. 50# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. 51OPERATOR_SDK_VERSION ?= v1.41.1 52# Image URL to use all building/pushing image targets 53IMG ?= buoy.cr/evan.jarrett.net/loom:latest 54 55# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) 56ifeq (,$(shell go env GOBIN)) 57GOBIN=$(shell go env GOPATH)/bin 58else 59GOBIN=$(shell go env GOBIN) 60endif 61 62# CONTAINER_TOOL defines the container tool to be used for building images. 63# Be aware that the target commands are only tested with Docker which is 64# scaffolded by default. However, you might want to replace it to use other 65# tools. (i.e. podman) 66CONTAINER_TOOL ?= docker 67 68# Setting SHELL to bash allows bash commands to be executed by recipes. 69# Options are set to exit when a recipe line exits non-zero or a piped command fails. 70SHELL = /usr/bin/env bash -o pipefail 71.SHELLFLAGS = -ec 72 73.PHONY: all 74all: build 75 76##@ General 77 78# The help target prints out all targets with their descriptions organized 79# beneath their categories. The categories are represented by '##@' and the 80# target descriptions by '##'. The awk command is responsible for reading the 81# entire set of makefiles included in this invocation, looking for lines of the 82# file as xyz: ## something, and then pretty-format the target and help. Then, 83# if there's a line with ##@ something, that gets pretty-printed as a category. 84# More info on the usage of ANSI control characters for terminal formatting: 85# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters 86# More info on the awk command: 87# http://linuxcommand.org/lc3_adv_awk.php 88 89.PHONY: help 90help: ## Display this help. 91 @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 92 93##@ Development 94 95.PHONY: manifests 96manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. 97 $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases 98 99.PHONY: generate 100generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. 101 $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." 102 103.PHONY: proto 104proto: ## Generate protobuf and gRPC code. 105 buf generate 106 107.PHONY: fmt 108fmt: ## Run go fmt against code. 109 go fmt ./... 110 111.PHONY: vet 112vet: ## Run go vet against code. 113 go vet ./... 114 115.PHONY: test 116test: manifests generate fmt vet setup-envtest ## Run tests. 117 KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out 118 119# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'. 120# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. 121# CertManager is installed by default; skip with: 122# - CERT_MANAGER_INSTALL_SKIP=true 123KIND_CLUSTER ?= loom-test-e2e 124 125.PHONY: setup-test-e2e 126setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist 127 @command -v $(KIND) >/dev/null 2>&1 || { \ 128 echo "Kind is not installed. Please install Kind manually."; \ 129 exit 1; \ 130 } 131 @case "$$($(KIND) get clusters)" in \ 132 *"$(KIND_CLUSTER)"*) \ 133 echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \ 134 *) \ 135 echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \ 136 $(KIND) create cluster --name $(KIND_CLUSTER) ;; \ 137 esac 138 139.PHONY: test-e2e 140test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. 141 KIND_CLUSTER=$(KIND_CLUSTER) go test ./test/e2e/ -v -ginkgo.v 142 $(MAKE) cleanup-test-e2e 143 144.PHONY: cleanup-test-e2e 145cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests 146 @$(KIND) delete cluster --name $(KIND_CLUSTER) 147 148.PHONY: lint 149lint: golangci-lint ## Run golangci-lint linter 150 $(GOLANGCI_LINT) run 151 152.PHONY: lint-fix 153lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes 154 $(GOLANGCI_LINT) run --fix 155 156.PHONY: lint-config 157lint-config: golangci-lint ## Verify golangci-lint linter configuration 158 $(GOLANGCI_LINT) config verify 159 160##@ Build 161 162.PHONY: build 163build: manifests generate fmt vet ## Build manager binary. 164 go build -o bin/manager cmd/controller/main.go 165 166.PHONY: run 167run: manifests generate fmt vet ## Run a controller from your host. 168 go run ./cmd/controller/main.go 169 170# Build multi-arch docker image using buildx (native builds per arch due to CGO) 171# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ 172.PHONY: docker-build 173docker-build: setup-buildx ## Build and push multi-arch docker image. 174 $(CONTAINER_TOOL) buildx build \ 175 --builder loom-builder \ 176 --platform=linux/amd64,linux/arm64 \ 177 --push \ 178 --tag ${IMG} \ 179 -f Dockerfile . 180 181.PHONY: docker-build-local 182docker-build-local: ## Build docker image for local arch only (no push). 183 $(CONTAINER_TOOL) build -t ${IMG} . 184 185.PHONY: setup-buildx 186setup-buildx: ## Set up buildx builder with credential access for multi-arch builds 187 @echo "Setting up loom-builder with credential access..." 188 # Remove existing builder if present 189 - $(CONTAINER_TOOL) buildx rm loom-builder 2>/dev/null || true 190 # Create builder with Docker config and credential helper mounts 191 $(CONTAINER_TOOL) buildx create --name loom-builder \ 192 --driver docker-container \ 193 --driver-opt network=host \ 194 --driver-opt "env.PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ 195 --config /dev/stdin <<< 'debug = true' || true 196 # Bootstrap the builder to mount credentials 197 $(CONTAINER_TOOL) buildx inspect --bootstrap loom-builder 198 # Copy Docker config and credential helper into the builder container 199 @echo "Copying credentials to builder container..." 200 @$(CONTAINER_TOOL) exec buildx_buildkit_loom-builder0 mkdir -p /root/.docker /usr/local/sbin 2>/dev/null || true 201 $(CONTAINER_TOOL) cp $(HOME)/.docker/config.json buildx_buildkit_loom-builder0:/root/.docker/config.json 202 @if [ -f /usr/local/sbin/docker-credential-atcr ]; then \ 203 echo "Copying credential helper to builder container..."; \ 204 $(CONTAINER_TOOL) cp /usr/local/sbin/docker-credential-atcr buildx_buildkit_loom-builder0:/usr/local/sbin/docker-credential-atcr && \ 205 $(CONTAINER_TOOL) exec buildx_buildkit_loom-builder0 chmod +x /usr/local/sbin/docker-credential-atcr; \ 206 echo "Installing glibc compatibility for credential helper (Alpine container)..."; \ 207 $(CONTAINER_TOOL) exec buildx_buildkit_loom-builder0 apk add --no-cache gcompat libc6-compat 2>/dev/null || \ 208 echo "⚠ Could not install glibc compatibility, credential helper may not work"; \ 209 echo "✓ Credential helper installed in builder"; \ 210 else \ 211 echo "⚠ Credential helper not found, will rely on username/password auth"; \ 212 fi 213 @echo "✓ Builder setup complete!" 214 215 216.PHONY: test-registry-auth 217test-registry-auth: ## Test registry authentication before building 218 @echo "Testing registry authentication for buoy.cr..." 219 @if [ -f /usr/local/sbin/docker-credential-atcr ]; then \ 220 echo "Testing credential helper..."; \ 221 echo "buoy.cr" | docker-credential-atcr get && echo "✓ Credential helper working!" || echo "✗ Credential helper failed"; \ 222 else \ 223 echo "⚠ Credential helper not found at /usr/local/sbin/docker-credential-atcr"; \ 224 fi 225 @echo "" 226 @echo "Testing Docker config..." 227 @if [ -f $(HOME)/.docker/config.json ]; then \ 228 echo "✓ Docker config exists at $(HOME)/.docker/config.json"; \ 229 cat $(HOME)/.docker/config.json | grep -q "buoy.cr" && echo "✓ buoy.cr found in config" || echo "⚠ buoy.cr not found in config"; \ 230 else \ 231 echo "✗ Docker config not found"; \ 232 fi 233 @echo "" 234 @echo "Testing registry access with docker pull (this will fail if auth is broken)..." 235 @$(CONTAINER_TOOL) pull buoy.cr/evan.jarrett.net/loom-runner:latest 2>/dev/null && echo "✓ Can pull from registry!" || echo "⚠ Cannot pull from registry (may not exist yet)" 236 237.PHONY: build-installer 238build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. 239 mkdir -p dist 240 cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} 241 $(KUSTOMIZE) build config/default > dist/install.yaml 242 243##@ Deployment 244 245ifndef ignore-not-found 246 ignore-not-found = false 247endif 248 249.PHONY: install 250install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. 251 $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - 252 253.PHONY: uninstall 254uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. 255 $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - 256 257# OVERLAY selects the kustomize overlay to use (default, prod, etc.) 258# Use 'make deploy OVERLAY=prod' for cluster-specific settings 259OVERLAY ?= prod 260 261.PHONY: deploy 262deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. 263 cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} 264ifeq ($(OVERLAY),default) 265 $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - 266else 267 $(KUSTOMIZE) build config/overlays/$(OVERLAY) | $(KUBECTL) apply -f - 268endif 269 @echo "Waiting for deployment to be ready and forcing rollout to pull fresh image..." 270 $(KUBECTL) rollout restart deployment/loom-controller-manager -n loom-system 271 $(KUBECTL) rollout status deployment/loom-controller-manager -n loom-system --timeout=120s 272 273.PHONY: undeploy 274undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. 275 $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - 276 277##@ Dependencies 278 279## Location to install dependencies to 280LOCALBIN ?= $(shell pwd)/bin 281$(LOCALBIN): 282 mkdir -p $(LOCALBIN) 283 284## Tool Binaries 285KUBECTL ?= kubectl 286KIND ?= kind 287KUSTOMIZE ?= $(LOCALBIN)/kustomize 288CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen 289ENVTEST ?= $(LOCALBIN)/setup-envtest 290GOLANGCI_LINT = $(LOCALBIN)/golangci-lint 291 292## Tool Versions 293KUSTOMIZE_VERSION ?= v5.6.0 294CONTROLLER_TOOLS_VERSION ?= v0.18.0 295#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20) 296ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}') 297#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) 298ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}') 299GOLANGCI_LINT_VERSION ?= v2.11.4 300 301.PHONY: kustomize 302kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. 303$(KUSTOMIZE): $(LOCALBIN) 304 $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) 305 306.PHONY: controller-gen 307controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. 308$(CONTROLLER_GEN): $(LOCALBIN) 309 $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) 310 311.PHONY: setup-envtest 312setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory. 313 @echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..." 314 @$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \ 315 echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \ 316 exit 1; \ 317 } 318 319.PHONY: envtest 320envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. 321$(ENVTEST): $(LOCALBIN) 322 $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) 323 324.PHONY: golangci-lint 325golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. 326$(GOLANGCI_LINT): $(LOCALBIN) 327 $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) 328 329# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist 330# $1 - target path with name of binary 331# $2 - package url which can be installed 332# $3 - specific version of package 333define go-install-tool 334@[ -f "$(1)-$(3)" ] || { \ 335set -e; \ 336package=$(2)@$(3) ;\ 337echo "Downloading $${package}" ;\ 338rm -f $(1) || true ;\ 339GOBIN=$(LOCALBIN) go install $${package} ;\ 340mv $(1) $(1)-$(3) ;\ 341} ;\ 342ln -sf $(1)-$(3) $(1) 343endef 344 345.PHONY: operator-sdk 346OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk 347operator-sdk: ## Download operator-sdk locally if necessary. 348ifeq (,$(wildcard $(OPERATOR_SDK))) 349ifeq (, $(shell which operator-sdk 2>/dev/null)) 350 @{ \ 351 set -e ;\ 352 mkdir -p $(dir $(OPERATOR_SDK)) ;\ 353 OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ 354 curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ 355 chmod +x $(OPERATOR_SDK) ;\ 356 } 357else 358OPERATOR_SDK = $(shell which operator-sdk) 359endif 360endif 361 362.PHONY: bundle 363bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. 364 $(OPERATOR_SDK) generate kustomize manifests -q 365 cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) 366 $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) 367 $(OPERATOR_SDK) bundle validate ./bundle 368 369.PHONY: bundle-build 370bundle-build: ## Build the bundle image. 371 $(CONTAINER_TOOL) build -f bundle.Dockerfile -t $(BUNDLE_IMG) . 372 373.PHONY: bundle-push 374bundle-push: ## Push the bundle image. 375 $(MAKE) docker-push IMG=$(BUNDLE_IMG) 376 377.PHONY: opm 378OPM = $(LOCALBIN)/opm 379opm: ## Download opm locally if necessary. 380ifeq (,$(wildcard $(OPM))) 381ifeq (,$(shell which opm 2>/dev/null)) 382 @{ \ 383 set -e ;\ 384 mkdir -p $(dir $(OPM)) ;\ 385 OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ 386 curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.55.0/$${OS}-$${ARCH}-opm ;\ 387 chmod +x $(OPM) ;\ 388 } 389else 390OPM = $(shell which opm) 391endif 392endif 393 394# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). 395# These images MUST exist in a registry and be pull-able. 396BUNDLE_IMGS ?= $(BUNDLE_IMG) 397 398# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). 399CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) 400 401# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. 402ifneq ($(origin CATALOG_BASE_IMG), undefined) 403FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) 404endif 405 406# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. 407# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: 408# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator 409.PHONY: catalog-build 410catalog-build: opm ## Build a catalog image. 411 $(OPM) index add --container-tool $(CONTAINER_TOOL) --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) 412 413# Push the catalog image. 414.PHONY: catalog-push 415catalog-push: ## Push a catalog image. 416 $(MAKE) docker-push IMG=$(CATALOG_IMG) 417 418##@ Helm 419 420.PHONY: helm-sync 421helm-sync: manifests ## Sync CRDs to Helm chart 422 @echo "Syncing CRDs to helm/loom/crds/" 423 @mkdir -p helm/loom/crds 424 cp config/crd/bases/*.yaml helm/loom/crds/ 425 426.PHONY: helm-lint 427helm-lint: ## Lint Helm chart 428 helm lint helm/loom 429 430.PHONY: helm-template 431helm-template: ## Render Helm templates for validation 432 helm template test helm/loom --set spindle.hostname=test.example.com --set spindle.owner=did:plc:test --debug 433 434.PHONY: helm-package 435helm-package: helm-sync ## Package Helm chart 436 helm package helm/loom 437 438.PHONY: version-sync 439version-sync: ## Sync versions to Chart.yaml 440 @sed -i 's/^version: .*/version: $(VERSION)/' helm/loom/Chart.yaml 441 @sed -i 's/^appVersion: .*/appVersion: "$(VERSION)"/' helm/loom/Chart.yaml