Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "Kubebuilder DevContainer",
"image": "docker.io/golang:1.24",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/git:1": {}
},

"runArgs": ["--network=host"],

"customizations": {
"vscode": {
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"extensions": [
"ms-kubernetes-tools.vscode-kubernetes-tools",
"ms-azuretools.vscode-docker"
]
}
},

"onCreateCommand": "bash .devcontainer/post-install.sh"
}
23 changes: 23 additions & 0 deletions .devcontainer/post-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
set -x

curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind
mv ./kind /usr/local/bin/kind

curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/amd64
chmod +x kubebuilder
mv kubebuilder /usr/local/bin/

KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/kubectl

docker network create -d=bridge --subnet=172.19.0.0/24 kind

kind version
kubebuilder version
docker --version
go version
kubectl version --client
4 changes: 2 additions & 2 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ jobs:
RUN_UNIT_TESTS: true
RUN_INTEGRATION_TESTS: true
RUN_HELMCHART_TEST: true
GO_VERSION: ~1.22
OPERATOR_SDK_VERSION: v1.31.0
GO_VERSION: ~1.24
OPERATOR_SDK_VERSION: v1.41.0
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.22 AS builder
FROM golang:1.24 AS builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand All @@ -10,12 +10,12 @@ COPY go.sum go.sum
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY controllers/ controllers/
COPY internal/controller/ internal/controller/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
76 changes: 44 additions & 32 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ VAULT_VERSION ?= 1.19.0
VAULT_CHART_VERSION ?= 0.30.0
# Set the Operator SDK version to use. By default, what is installed on the system is used.
# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit.
OPERATOR_SDK_VERSION ?= v1.31.0
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION ?= 1.29.0
OPERATOR_SDK_VERSION ?= v1.41.0

CONTROLLER_TOOLS_VERSION ?= v0.18.0
GOLANGCI_LINT_VERSION ?= v2.1.0
GO ?= go

CONTROLLER_TOOLS_VERSION ?= v0.14.0
ENVTEST_VERSION ?= release-0.17
GOLANGCI_LINT_VERSION ?= v1.59.1
ENVTEST_VERSION := $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION := $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')

# VERSION defines the project version for the bundle.
# Update this value when you upgrade the version of your project.
Expand Down Expand Up @@ -69,6 +71,7 @@ BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)

# Image URL to use all building/pushing image targets
IMG ?= controller:latest
PLATFORMS ?= linux/amd64,linux/arm64
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false"

Expand Down Expand Up @@ -124,15 +127,17 @@ vet: ## Run go vet against code.
go vet ./...

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: manifests generate fmt vet setup-envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
go test ./... -coverprofile cover.out

# note: envtest requires docker, podman will not work
.PHONY: integration
integration: kind-setup deploy-vault deploy-ingress vault manifests generate fmt vet envtest ## Run tests.
export VAULT_TOKEN=$$($(KUBECTL) get secret vault-init -n vault -o jsonpath='{.data.root_token}' | base64 -d) ;\
export VAULT_ADDR="http://localhost:8200" ;\
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out --tags=integration
integration: kind-setup deploy-vault deploy-ingress vault manifests generate fmt vet setup-envtest ## Run tests.
VAULT_TOKEN="$$($(KUBECTL) get secret vault-init -n vault -o jsonpath='{.data.root_token}' | base64 -d)" \
VAULT_ADDR="http://localhost:8200" \
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
go test ./... -coverprofile cover.out --tags=integration

.PHONY: deploy-ingress
deploy-ingress: kubectl helm
Expand Down Expand Up @@ -178,11 +183,11 @@ ldap-setup: kind-setup vault

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager main.go
go build -o bin/manager ./cmd/main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
go run ./cmd/main.go

.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
Expand All @@ -192,6 +197,13 @@ docker-build: test ## Build docker image with the manager.
docker-push: ## Push docker image with the manager.
docker push ${IMG}

.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
- docker buildx create --name project-v3-builder
docker buildx use project-v3-builder
- docker buildx build --push --platform=$(PLATFORMS) --tag $(IMG) -f Dockerfile .
- docker buildx rm project-v3-builder

.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
Expand Down Expand Up @@ -235,8 +247,9 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint

## Tool Versions
# above
$(ENVTEST): $(LOCALBIN)
@mkdir -p $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@$(ENVTEST_VERSION)

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
Expand All @@ -248,29 +261,24 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))

.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))

.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f "$(1)-$(3)" ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
rm -f $(1) || true ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv $(1) $(1)-$(3) ;\
} ;\
set -e; \
package=$(2)@$(3); \
echo "Downloading $${package}"; \
rm -f $(1) || true; \
GOBIN=$(LOCALBIN) $(GO) install $${package}; \
mv $(1) $(1)-$(3); \
}; \
ln -sf $(1)-$(3) $(1)
endef

Expand Down Expand Up @@ -315,8 +323,7 @@ ifeq (,$(shell which opm 2>/dev/null))
set -e ;\
mkdir -p $(dir $(OPM)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
chmod +x $(OPM) ;\
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.55.0/$${OS}-$${ARCH}-opm ;\
}
else
OPM = $(shell which opm)
Expand Down Expand Up @@ -468,3 +475,8 @@ endif
.PHONY: clean
clean:
rm -rf $(LOCALBIN) ./bundle ./bundle-* ./charts

.PHONY: setup-envtest
setup-envtest: $(ENVTEST)
@$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \
echo "Error setting up envtest"; exit 1; }
2 changes: 1 addition & 1 deletion PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: redhat.io
layout:
- go.kubebuilder.io/v3
- go.kubebuilder.io/v4
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
Expand Down
46 changes: 32 additions & 14 deletions api/v1alpha1/authenginemount_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ limitations under the License.
package v1alpha1

import (
"context"
"errors"
"reflect"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

Expand All @@ -40,37 +40,51 @@ func (r *AuthEngineMount) SetupWebhookWithManager(mgr ctrl.Manager) error {

//+kubebuilder:webhook:path=/mutate-redhatcop-redhat-io-v1alpha1-authenginemount,mutating=true,failurePolicy=fail,sideEffects=None,groups=redhatcop.redhat.io,resources=authenginemounts,verbs=create,versions=v1alpha1,name=mauthenginemount.kb.io,admissionReviewVersions={v1,v1beta1}

var _ webhook.Defaulter = &AuthEngineMount{}
var _ admission.CustomDefaulter = &AuthEngineMount{}

// Default implements webhook.Defaulter so a webhook will be registered for the type
func (r *AuthEngineMount) Default() {
authenginemountlog.Info("default", "name", r.Name)
func (r *AuthEngineMount) Default(_ context.Context, obj runtime.Object) error {
cr, ok := obj.(*AuthEngineMount)
if !ok {
return nil
}
authenginemountlog.Info("default", "name", cr.Name)
return nil
}

// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
//+kubebuilder:webhook:path=/validate-redhatcop-redhat-io-v1alpha1-authenginemount,mutating=false,failurePolicy=fail,sideEffects=None,groups=redhatcop.redhat.io,resources=authenginemounts,verbs=update,versions=v1alpha1,name=vauthenginemount.kb.io,admissionReviewVersions={v1,v1beta1}

var _ webhook.Validator = &AuthEngineMount{}
var _ admission.CustomValidator = &AuthEngineMount{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r *AuthEngineMount) ValidateCreate() (admission.Warnings, error) {
authenginemountlog.Info("validate create", "name", r.Name)
func (r *AuthEngineMount) ValidateCreate(_ context.Context, obj runtime.Object) (admission.Warnings, error) {
cr, ok := obj.(*AuthEngineMount)
if !ok {
return nil, nil
}
authenginemountlog.Info("validate create", "name", cr.Name)

// TODO(user): fill in your validation logic upon object creation.
return nil, nil
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (r *AuthEngineMount) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
authenginemountlog.Info("validate update", "name", r.Name)
func (r *AuthEngineMount) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
newCR, ok := newObj.(*AuthEngineMount)
if !ok {
return nil, nil
}
oldCR, _ := oldObj.(*AuthEngineMount)
authenginemountlog.Info("validate update", "name", newCR.Name)

// the path cannot be updated
if r.Spec.Path != old.(*AuthEngineMount).Spec.Path {
if newCR.Spec.Path != oldCR.Spec.Path {
return nil, errors.New("spec.path cannot be updated")
}
// only mount config can be modified
oldMount := old.(*AuthEngineMount).Spec.AuthMount
newMount := r.Spec.AuthMount
oldMount := oldCR.Spec.AuthMount
newMount := newCR.Spec.AuthMount
oldMount.Config = AuthMountConfig{}
newMount.Config = AuthMountConfig{}
if !reflect.DeepEqual(oldMount, newMount) {
Expand All @@ -80,8 +94,12 @@ func (r *AuthEngineMount) ValidateUpdate(old runtime.Object) (admission.Warnings
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (r *AuthEngineMount) ValidateDelete() (admission.Warnings, error) {
authenginemountlog.Info("validate delete", "name", r.Name)
func (r *AuthEngineMount) ValidateDelete(_ context.Context, obj runtime.Object) (admission.Warnings, error) {
cr, ok := obj.(*AuthEngineMount)
if !ok {
return nil, nil
}
authenginemountlog.Info("validate delete", "name", cr.Name)

// TODO(user): fill in your validation logic upon object deletion.
return nil, nil
Expand Down
Loading
Loading