Skip to content

Commit

Permalink
Merge pull request #9 from Peefy/feat-mutator
Browse files Browse the repository at this point in the history
feat: impl mutator using KRM KCL spec.
  • Loading branch information
Peefy authored Aug 31, 2023
2 parents c1c3c6c + 31cacf5 commit af1d2a0
Show file tree
Hide file tree
Showing 41 changed files with 1,768 additions and 989 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ go.work
/vendor
.tools
.gopath
.DS_store
45 changes: 16 additions & 29 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,33 +1,20 @@
# Build the manager binary
FROM golang:1.19 as builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot

ENV GO111MODULE=on \
GOPROXY=https://goproxy.cn,direct

WORKDIR /

COPY . .

RUN GOOS=linux GOARCH=amd64 go build -o manager

FROM kcllang/kcl

WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532
COPY --from=builder /manager .

ENV KCL_GO_DISABLE_ARTIFACT=on
ENV LANG="en_US.UTF-8"

ENTRYPOINT ["/manager"]
104 changes: 77 additions & 27 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ ifeq ($(USE_IMAGE_DIGESTS), true)
endif

# Image URL to use all building/pushing image targets
IMG ?= controller:latest
IMG ?= kcllang/webhookserver
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.26.0
ENVTEST_K8S_VERSION = 1.28.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand All @@ -63,6 +63,31 @@ endif
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

# Current Webhook version
VERSION ?= 1.0
# Default bundle image tag
BUNDLE_IMG ?= controller-bundle:$(VERSION)
# Options for 'bundle-build'
ifneq ($(origin CHANNELS), undefined)
BUNDLE_CHANNELS := --channels=$(CHANNELS)
endif
ifneq ($(origin DEFAULT_CHANNEL), undefined)
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
endif
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)

# Image URL to use all building/pushing image targets
IMG ?= controller:latest

WEBHOOK_NAME ?=$(shell basename -z `pwd`)

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

.PHONY: all
all: build

Expand Down Expand Up @@ -108,9 +133,21 @@ test: manifests generate fmt vet envtest ## Run tests.
##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
build: ## Build binaries.
make manager

.PHONY: build
build-linux: ## Build binaries.
make manager-linux

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

.PHONY: manager-linux
manager-linux: generate fmt vet
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o build/bin/manager main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
Expand All @@ -119,14 +156,14 @@ run: manifests generate fmt vet ## Run a controller from your host.
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
docker build -t ${IMG} .
docker-build: ## Build docker image with the manager.
docker build -t $(IMG) .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
docker push ${IMG}

# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple
# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/
# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/
Expand Down Expand Up @@ -155,12 +192,13 @@ install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~

.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 -
$(KUSTOMIZE) build config/crd | kubectl delete -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 -
deploy: #manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/webhook && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > config/all.yaml
kubectl apply -f config/all.yaml

.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.
Expand Down Expand Up @@ -276,13 +314,20 @@ CONTROLLER_TOOLS_VERSION ?= v0.11.1

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
$(KUSTOMIZE): $(LOCALBIN)
@if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \
echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \
rm -rf $(LOCALBIN)/kustomize; \
fi
test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); }
kustomize:
ifeq (, $(shell which kustomize))
@{ \
set -e ;\
KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$KUSTOMIZE_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/kustomize/kustomize/[email protected] ;\
rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\
}
KUSTOMIZE=$(GOBIN)/kustomize
else
KUSTOMIZE=$(shell which kustomize)
endif

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
Expand All @@ -298,18 +343,10 @@ $(ENVTEST): $(LOCALBIN)
.PHONY: bundle
bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files.
operator-sdk generate kustomize manifests -q
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS)
cd config/webhook && $(KUSTOMIZE) edit set image controller=$(IMG)
$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
operator-sdk bundle validate ./bundle

.PHONY: bundle-build
bundle-build: ## Build the bundle image.
docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .

.PHONY: bundle-push
bundle-push: ## Push the bundle image.
$(MAKE) docker-push IMG=$(BUNDLE_IMG)

.PHONY: opm
OPM = ./bin/opm
opm: ## Download opm locally if necessary.
Expand Down Expand Up @@ -432,3 +469,16 @@ codegen-applyconfigurations: $(APPLYCONFIGURATION_GEN) ## Generate apply configu

.PHONY: codegen-client-all
codegen-client-all: codegen-register codegen-defaulters codegen-applyconfigurations codegen-client-clientset codegen-client-listers codegen-client-informers ## Generate clientset, listers and informers

.PHONY: codegen-webhook
codegen-webhook:
operator-sdk create webhook --group krm.kcl.dev --version v1alpha1 --kind KCLRun --defaulting --programmatic-validation

# Generate helm chart
helmchart: kustomize
mkdir -p ./charts/${WEBHOOK_NAME}/templates
cp ./config/helmchart/templates/* ./charts/${WEBHOOK_NAME}/templates
$(KUSTOMIZE) build ./config/helmchart | sed 's/release-namespace/{{.Release.Namespace}}/' > ./charts/${WEBHOOK_NAME}/templates/rbac.yaml
version=${VERSION} envsubst < ./config/helmchart/Chart.yaml.tpl > ./charts/${WEBHOOK_NAME}/Chart.yaml
version=${VERSION} image_repo=$${IMG%:*} envsubst < ./config/helmchart/values.yaml.tpl > ./charts/${WEBHOOK_NAME}/values.yaml
helm lint ./charts/${WEBHOOK_NAME}
69 changes: 58 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,74 @@ KCL Operator provides cluster integration, allowing you to use Access Webhook to

![architecture](./images/arch.png)

## CR Example
## Developing

+ Install Go 1.20+
+ Install Kubectl and Kustomize
+ Install [Operator SDK](https://sdk.operatorframework.io/)
+ Prepare a Kubernetes Cluster e.g., K3d

Run `make help` to get the help.

## Quick Start

1. Deploy the KCL Operator.

```shell
make deploy
```

Use the following command to watch and wait the pod status is Running.

```shell
kubectl get po
```

```yaml
2. Deploy the KCL source

```shell
kubectl apply -f- << EOF
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: set-annotation
spec:
params:
annotations:
config.kubernetes.io/local-config: "true"
source: oci://ghcr.io/kcl-lang/set-annotation
source: |
items = [item | {
metadata.annotations: {
"managed-by" = "kcl-operator"
}
} for item in option("items")]
EOF
```

## Developing
3. Validate the mutation result by creating a nginx Pod YAML.

+ Install Go 1.20+
+ Install [Operator SDK](https://sdk.operatorframework.io/)
```shell
kubectl apply -f- << EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
annotations:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF
kubectl get po nginx -o yaml | grep kcl-operator
```

Run `make help` to get the help.
The output is

```shell
managed-by: kcl-operator
```

We can find the annotation `managed-by=kcl-operator` is added on the pod.

## Guides for Developing KCL

Expand All @@ -57,4 +105,3 @@ See [here](https://kcl-lang.io/docs/reference/lang/tour) to study more features
## Examples

See [here](https://github.com/kcl-lang/krm-kcl/tree/main/examples) for more examples.

Loading

0 comments on commit af1d2a0

Please sign in to comment.