diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..56bd43a36 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: Release +on: + push: + tags: + - "*" + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Create Release Artifacts + run: make release + env: + RELEASE_TAG: ${{ github.ref_name }} + - name: Upload Release Artifacts + uses: softprops/action-gh-release@v1 + with: + files: | + ./release + - name: Docker Meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + linode/cluster-api-provider-linode + tags: | + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} + type=semver,pattern={{raw}},value=${{ github.ref_name }} + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Build and Push to Docker Hub + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitignore b/.gitignore index 8564cb648..37ee674bd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ cover.out kubeconfig* .devbox/* docs/book +release/* diff --git a/Makefile b/Makefile index 625ae2053..dca7b3d9f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ - -# Image URL to use all building/pushing image targets -IMG ?= controller:latest +REGISTRY ?= docker.io/linode +IMAGE_NAME ?= cluster-api-provider-linode +CONTROLLER_IMAGE ?= $(REGISTRY)/$(IMAGE_NAME) +TAG ?= dev # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.28.0 OS=$(shell uname -s | tr '[:upper:]' '[:lower:]') @@ -47,11 +48,22 @@ all: build # More info on the awk command: # http://linuxcommand.org/lc3_adv_awk.php + +## -------------------------------------- +## Help +## -------------------------------------- + +##@ Help: + .PHONY: help help: ## Display this help. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\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) -##@ Development +## -------------------------------------- +## Generate +## -------------------------------------- + +##@ Generate: .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. @@ -61,6 +73,12 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." +## -------------------------------------- +## Development +## -------------------------------------- + +##@ Development: + .PHONY: fmt fmt: ## Run go fmt against code. go fmt ./... @@ -85,6 +103,12 @@ nilcheck: nilaway ## Run nil check against code. vulncheck: govulncheck ## Run vulnerability check against code. govulncheck ./... +## -------------------------------------- +## Testing +## -------------------------------------- + +##@ Testing: + .PHONY: test test: manifests generate fmt vet envtest ## Run tests. KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test -race -timeout 60s ./... -coverprofile cover.out @@ -101,7 +125,11 @@ _e2etest-infra: kind ctlptl tilt kuttl kustomize clusterctl envsubst _e2etest: manifests generate envsubst _e2etest-infra ROOT_DIR="$(PWD)" $(KUTTL) test --config e2e/kuttl-config.yaml -##@ Build +## -------------------------------------- +## Build +## -------------------------------------- + +##@ Build: .PHONY: build build: manifests generate fmt vet ## Build manager binary. @@ -116,11 +144,11 @@ run: manifests generate fmt vet ## Run a controller from your host. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ .PHONY: docker-build docker-build: ## Build docker image with the manager. - $(CONTAINER_TOOL) build $(BUILD_ARGS) -t ${IMG} . + $(CONTAINER_TOOL) build $(BUILD_ARGS) . -t $(CONTROLLER_IMAGE):$(TAG) .PHONY: docker-push docker-push: ## Push docker image with the manager. - $(CONTAINER_TOOL) push ${IMG} + $(CONTAINER_TOOL) push $(CONTROLLER_IMAGE):$(TAG) # 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: @@ -135,40 +163,63 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - $(CONTAINER_TOOL) buildx create --name project-v3-builder $(CONTAINER_TOOL) buildx use project-v3-builder - - $(CONTAINER_TOOL) buildx build $(BUILD_ARGS) --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx build $(BUILD_ARGS) --push --platform=$(PLATFORMS) --tag $(CONTROLLER_IMAGE):$(TAG) -f Dockerfile.cross . - $(CONTAINER_TOOL) buildx rm project-v3-builder rm Dockerfile.cross -##@ Deployment +## -------------------------------------- +## Deployment +## -------------------------------------- + +##@ Deployment: ifndef ignore-not-found ignore-not-found = false endif -.PHONY: install -install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - - -.PHONY: uninstall -uninstall: 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. - $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - - -.PHONY: deploy -deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - - -.PHONY: undeploy -undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - - .PHONY: tilt-cluster tilt-cluster: ctlptl tilt kind clusterctl @echo -n "LINODE_TOKEN=$(LINODE_TOKEN)" > config/default/.env.linode $(CTLPTL) apply -f .tilt/ctlptl-config.yaml $(TILT) up --stream -##@ Build Dependencies +## -------------------------------------- +## Release +## -------------------------------------- + +##@ Release: + +RELEASE_DIR ?= release +RELEASE_TAG ?= $(shell git describe --abbrev=0 2>/dev/null) + +.PHONY: set-manifest-image +set-manifest-image: ## Update kustomize image patch file for default resource. + sed -i'' -e 's@image: .*@image: '"${MANIFEST_IMG}:${MANIFEST_TAG}"'@' ./config/default/manager_image_patch.yaml + +.PHONY: release +release: $(KUSTOMIZE) + rm -rf $(RELEASE_DIR) + mkdir -p $(RELEASE_DIR)/ + $(MAKE) set-manifest-image MANIFEST_IMG=$(REGISTRY)/$(IMAGE_NAME) MANIFEST_TAG=$(RELEASE_TAG) + $(KUSTOMIZE) build config/default > $(RELEASE_DIR)/infrastructure-components.yaml + cp templates/cluster-template* $(RELEASE_DIR)/ + cp metadata.yaml $(RELEASE_DIR)/metadata.yaml + +## -------------------------------------- +## Cleanup +## -------------------------------------- + +##@ Cleanup: + +.PHONY: clean +clean: + rm -rf $(LOCALBIN) + +## -------------------------------------- +## Build Dependencies +## -------------------------------------- + +##@ Build Dependencies: ## Location to install dependencies to @@ -188,7 +239,12 @@ export PATH := $(CACHE_BIN):$(PATH) $(LOCALBIN): mkdir -p $(LOCALBIN) -## Tool Binaries +## -------------------------------------- +## Tooling Binaries +## -------------------------------------- + +##@ Tooling Binaries: + KUBECTL ?= kubectl KUSTOMIZE ?= $(LOCALBIN)/kustomize CTLPTL ?= $(LOCALBIN)/ctlptl @@ -290,7 +346,3 @@ $(NILAWAY): $(LOCALBIN) govulncheck: $(GOVULNC) ## Download govulncheck locally if necessary. $(GOVULNC): $(LOCALBIN) GOBIN=$(LOCALBIN) go install golang.org/x/vuln/cmd/govulncheck@$(GOVULNC_VERSION) - -.PHONY: clean -clean: - rm -rf $(LOCALBIN) diff --git a/Tiltfile b/Tiltfile index c89471563..d300d4722 100644 --- a/Tiltfile +++ b/Tiltfile @@ -1,34 +1,42 @@ load("ext://k8s_attach", "k8s_attach") -docker_build("controller", ".", only=("Dockerfile", "Makefile", "vendor","go.mod", "go.sum", "./api", "./cloud","./cmd", "./controller", "./util", "./version"), build_args={'VERSION': os.getenv("VERSION","")}) +docker_build( + "docker.io/linode/cluster-api-provider-linode", + context = ".", + only=("Dockerfile", "Makefile", "vendor","go.mod", "go.sum", "./api", "./cloud","./cmd", "./controller", "./util", "./version"), + build_args={'VERSION': os.getenv("VERSION","")}, +) local_resource( 'capi-controller-manager', cmd='EXP_CLUSTER_RESOURCE_SET=true clusterctl init --addon helm', ) -k8s_yaml(kustomize('config/default')) - -# get generated secret name so we can categorize it -token_secret_name = str(local('kustomize build config/default | grep -m1 "name: cluster-api-provider-linode-token-"', quiet=True, echo_off=True)).split()[1] +templated_yaml = local( + 'kustomize build config/default | envsubst', + env={'LINODE_TOKEN': os.getenv('LINODE_TOKEN')}, + quiet=True, + echo_off=True +) +k8s_yaml(templated_yaml) k8s_resource( - workload="cluster-api-provider-linode-controller-manager", + workload="capl-controller-manager", objects=[ - "cluster-api-provider-linode-system:namespace", + "capl-system:namespace", "linodeclusters.infrastructure.cluster.x-k8s.io:customresourcedefinition", "linodemachines.infrastructure.cluster.x-k8s.io:customresourcedefinition", "linodeclustertemplates.infrastructure.cluster.x-k8s.io:customresourcedefinition", "linodemachinetemplates.infrastructure.cluster.x-k8s.io:customresourcedefinition", "linodevpcs.infrastructure.cluster.x-k8s.io:customresourcedefinition", - "cluster-api-provider-linode-controller-manager:serviceaccount", - "cluster-api-provider-linode-leader-election-role:role", - "cluster-api-provider-linode-manager-role:clusterrole", - "cluster-api-provider-linode-metrics-reader:clusterrole", - "cluster-api-provider-linode-proxy-role:clusterrole", - "cluster-api-provider-linode-leader-election-rolebinding:rolebinding", - "cluster-api-provider-linode-manager-rolebinding:clusterrolebinding", - "cluster-api-provider-linode-proxy-rolebinding:clusterrolebinding", - "%s:secret" % token_secret_name + "capl-controller-manager:serviceaccount", + "capl-leader-election-role:role", + "capl-manager-role:clusterrole", + "capl-metrics-reader:clusterrole", + "capl-proxy-role:clusterrole", + "capl-leader-election-rolebinding:rolebinding", + "capl-manager-rolebinding:clusterrolebinding", + "capl-proxy-rolebinding:clusterrolebinding", + "capl-manager-credentials:secret", ] ) diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index ef232373f..e90807c7b 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -1,7 +1,8 @@ # common labels for CRD resources as required by # https://cluster-api.sigs.k8s.io/developer/providers/contracts.html#api-version-labels -commonLabels: - cluster.x-k8s.io/v1beta1: v1alpha1 +labels: + - pairs: + cluster.x-k8s.io/v1beta1: v1alpha1 # This kustomization.yaml is not intended to be run by itself, # since it depends on service name and namespace that are out of this kustomize package. diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 3120c0ce4..e45d9b5ac 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -1,23 +1,18 @@ # Adds namespace to all resources. -namespace: cluster-api-provider-linode-system +namespace: capl-system # Value of this field is prepended to the # names of all resources, e.g. a deployment named # "wordpress" becomes "alices-wordpress". # Note that it should also match with the prefix (text before '-') of the namespace # field above. -namePrefix: cluster-api-provider-linode- - -# Labels to add to all resources and selectors. -#labels: -#- includeSelectors: true -# pairs: -# someName: someValue +namePrefix: capl- resources: - ../crd - ../rbac - ../manager +- linode-token-secret.yaml # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml #- ../webhook @@ -26,18 +21,10 @@ resources: # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. #- ../prometheus -secretGenerator: - - name: token - envs: - - .env.linode - -patchesStrategicMerge: -# Protect the /metrics endpoint by putting it behind auth. -# If you want your controller-manager to expose the /metrics -# endpoint w/o any authn/z, please comment the following line. -- manager_auth_proxy_patch.yaml - - +patches: +- path: manager_auth_proxy_patch.yaml +- path: manager_image_patch.yaml +- path: manager_credentials_patch.yaml # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml diff --git a/config/default/linode-token-secret.yaml b/config/default/linode-token-secret.yaml new file mode 100644 index 000000000..8ce36f8af --- /dev/null +++ b/config/default/linode-token-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: manager-credentials +stringData: + apiToken: ${LINODE_TOKEN} diff --git a/config/default/manager_credentials_patch.yaml b/config/default/manager_credentials_patch.yaml new file mode 100644 index 000000000..12bd5de64 --- /dev/null +++ b/config/default/manager_credentials_patch.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + env: + - name: LINODE_TOKEN + valueFrom: + secretKeyRef: + key: apiToken + name: capl-manager-credentials diff --git a/config/default/manager_image_patch.yaml b/config/default/manager_image_patch.yaml new file mode 100644 index 000000000..2ee7174cf --- /dev/null +++ b/config/default/manager_image_patch.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - image: docker.io/linode/cluster-api-provider-linode:v0.1.0 + name: manager diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 22ae96fce..ce5859d2c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,4 +6,5 @@ - [Troubleshooting](./topics/troubleshooting.md) - [Addons](./topics/addons.md) - [Development](./developers/development.md) + - [Releasing](./developers/releasing.md) - [Reference](./reference/reference.md) diff --git a/docs/src/developers/releasing.md b/docs/src/developers/releasing.md new file mode 100644 index 000000000..56004319a --- /dev/null +++ b/docs/src/developers/releasing.md @@ -0,0 +1,61 @@ +# CAPL Releases + +## Release Cadence + +CAPL currently has no set release cadence. + +## Bug Fixes + +Any significant user-facing bug fix that lands in the main branch should be +backported to the current and previous release lines. + +## Versioning Scheme + +CAPL follows the [semantic versionining](https://semver.org/#semantic-versioning-200) specification. + +Example versions: + +- Pre-release: `v0.1.1-alpha.1` +- Minor release: `v0.1.0` +- Patch release: `v0.1.1` +- Major release: `v1.0.0` + +## Release Process + +### Update metadata.yaml (skip for patch releases) + +- Make sure [metadata.yaml](https://github.com/linode/cluster-api-provider-linode/blob/main/metadata.yaml) +is up to date and contains the new release with the correct Cluster API contract version. + - If not, open a PR to add it. + +### Create a release branch (skip for patch releases) + +- Create a release branch off of `main` named +`release-$(MAJOR_VERSION).$(MINOR_VERSION)` (e.g. release-0.1) + +### Create a tag for the release branch + +- After ensuring all desired changes for the release are in the release branch, +create a tag following semantic versioning (e.g. v0.1.1) +- Ensure the [release workflow](https://github.com/linode/cluster-api-provider-linode/actions/workflows/release.yml) +succeeds for the created tag to build and push the Docker image and generate +the [release artifacts](#expected-artifacts). + +### Release in GitHub + +- Create a [new release](https://github.com/linode/cluster-api-provider-linode/releases/new). + - Use the newly created tag + - Make sure to click "Generate Release Notes" + - Review the generated Release Notes and make any necessary changes. + - If the tag is a pre-release, make sure to check the "Set as a pre-release box" + +### Expected artifacts + +- A `infrastructure-components.yaml` file containing the resources needed to deploy to Kubernetes +- A `cluster-templates.yaml` file for each supported flavor +- A `metadata.yaml` file which maps release series to the Cluster API contract version + +### Communication + +1. Announce the release in the Kubernetes Slack on the +[#linode](https://kubernetes.slack.com/messages/CD4B15LUR) channel diff --git a/docs/src/topics/troubleshooting.md b/docs/src/topics/troubleshooting.md index afd95a905..8623ea886 100644 --- a/docs/src/topics/troubleshooting.md +++ b/docs/src/topics/troubleshooting.md @@ -53,7 +53,7 @@ kubectl get cluster-api To check the CAPL controller logs on the management cluster, run: ```bash -kubectl logs deploy/cluster-api-provider-linode-controller-manager -n cluster-api-provider-linode-system manager +kubectl logs deploy/capl-controller-manager -n capl-system manager ``` ### Checking cloud-init logs (Debian / Ubuntu) diff --git a/e2e/README.MD b/e2e/README.MD index e86283df6..078b94ab8 100644 --- a/e2e/README.MD +++ b/e2e/README.MD @@ -75,8 +75,8 @@ status: apiVersion: apps/v1 kind: Deployment metadata: - name: cluster-api-provider-linode-controller-manager - namespace: cluster-api-provider-linode-system + name: capl-controller-manager + namespace: capl-system status: availableReplicas: 1 ``` diff --git a/e2e/linodecluster-controller/minimal/00-assert.yaml b/e2e/linodecluster-controller/minimal/00-assert.yaml index 4107fd8f0..8a5b8dbab 100644 --- a/e2e/linodecluster-controller/minimal/00-assert.yaml +++ b/e2e/linodecluster-controller/minimal/00-assert.yaml @@ -9,7 +9,7 @@ status: apiVersion: apps/v1 kind: Deployment metadata: - name: cluster-api-provider-linode-controller-manager - namespace: cluster-api-provider-linode-system + name: capl-controller-manager + namespace: capl-system status: availableReplicas: 1 diff --git a/e2e/linodemachine-controller/byovpc/00-assert.yaml b/e2e/linodemachine-controller/byovpc/00-assert.yaml index 4107fd8f0..8a5b8dbab 100644 --- a/e2e/linodemachine-controller/byovpc/00-assert.yaml +++ b/e2e/linodemachine-controller/byovpc/00-assert.yaml @@ -9,7 +9,7 @@ status: apiVersion: apps/v1 kind: Deployment metadata: - name: cluster-api-provider-linode-controller-manager - namespace: cluster-api-provider-linode-system + name: capl-controller-manager + namespace: capl-system status: availableReplicas: 1 diff --git a/e2e/linodemachine-controller/minimal/00-assert.yaml b/e2e/linodemachine-controller/minimal/00-assert.yaml index 4107fd8f0..8a5b8dbab 100644 --- a/e2e/linodemachine-controller/minimal/00-assert.yaml +++ b/e2e/linodemachine-controller/minimal/00-assert.yaml @@ -9,7 +9,7 @@ status: apiVersion: apps/v1 kind: Deployment metadata: - name: cluster-api-provider-linode-controller-manager - namespace: cluster-api-provider-linode-system + name: capl-controller-manager + namespace: capl-system status: availableReplicas: 1 diff --git a/e2e/linodevpc-controller/minimal/00-assert.yaml b/e2e/linodevpc-controller/minimal/00-assert.yaml index 4107fd8f0..8a5b8dbab 100644 --- a/e2e/linodevpc-controller/minimal/00-assert.yaml +++ b/e2e/linodevpc-controller/minimal/00-assert.yaml @@ -9,7 +9,7 @@ status: apiVersion: apps/v1 kind: Deployment metadata: - name: cluster-api-provider-linode-controller-manager - namespace: cluster-api-provider-linode-system + name: capl-controller-manager + namespace: capl-system status: availableReplicas: 1 diff --git a/metadata.yaml b/metadata.yaml new file mode 100644 index 000000000..2e59b8dd3 --- /dev/null +++ b/metadata.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 +kind: Metadata +releaseSeries: +- major: 0 + minor: 1 + contract: v1beta1