Skip to content

Commit

Permalink
Initial base code for go/v4 alpha plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
NikhilSharmaWe committed May 19, 2022
1 parent a2b2be2 commit 6fb7b17
Show file tree
Hide file tree
Showing 360 changed files with 15,685 additions and 4 deletions.
7 changes: 7 additions & 0 deletions cmd/main.go
Expand Up @@ -25,6 +25,7 @@ import (
cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/model/stage"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
kustomizecommonv1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v1"
kustomizecommonv2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2"
Expand All @@ -41,6 +42,11 @@ func main() {
kustomizecommonv1.Plugin{},
golangv3.Plugin{},
)
// / Bundle plugin which built the golang projects scaffold by Kubebuilder go/v4
gov4Bundle, _ := plugin.NewBundle(golang.DefaultNameQualifier, plugin.Version{Number: 4, Stage: stage.Alpha},
kustomizecommonv2.Plugin{},
golangv3.Plugin{},
)

fs := machinery.Filesystem{
FS: afero.NewOsFs(),
Expand All @@ -57,6 +63,7 @@ func main() {
golangv2.Plugin{},
golangv3.Plugin{},
gov3Bundle,
gov4Bundle,
&kustomizecommonv1.Plugin{},
&kustomizecommonv2.Plugin{},
&declarativev1.Plugin{},
Expand Down
98 changes: 98 additions & 0 deletions test/e2e/v3/generate_test.go
Expand Up @@ -398,3 +398,101 @@ Count int `+"`"+`json:"count,omitempty"`+"`"+`
# create: true`, "#")).To(Succeed())

}

// GenerateV4 implements a go/v4(-alpha) plugin project defined by a TestContext.
func GenerateV4(kbc *utils.TestContext, crdAndWebhookVersion string) {
var err error

By("initializing a project")
err = kbc.Init(
"--plugins", "go/v4-alpha",
"--project-version", "3",
"--domain", kbc.Domain,
"--fetch-deps=false",
)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("creating API definition")
err = kbc.CreateAPI(
"--group", kbc.Group,
"--version", kbc.Version,
"--kind", kbc.Kind,
"--namespaced",
"--resource",
"--controller",
"--make=false",
"--crd-version", crdAndWebhookVersion,
)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("implementing the API")
ExpectWithOffset(1, pluginutil.InsertCode(
filepath.Join(kbc.Dir, "api", kbc.Version, fmt.Sprintf("%s_types.go", strings.ToLower(kbc.Kind))),
fmt.Sprintf(`type %sSpec struct {
`, kbc.Kind),
` // +optional
Count int `+"`"+`json:"count,omitempty"`+"`"+`
`)).Should(Succeed())

By("scaffolding mutating and validating webhooks")
err = kbc.CreateWebhook(
"--group", kbc.Group,
"--version", kbc.Version,
"--kind", kbc.Kind,
"--defaulting",
"--programmatic-validation",
"--webhook-version", crdAndWebhookVersion,
)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("implementing the mutating and validating webhooks")
err = pluginutil.ImplementWebhooks(filepath.Join(
kbc.Dir, "api", kbc.Version,
fmt.Sprintf("%s_webhook.go", strings.ToLower(kbc.Kind))))
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("uncomment kustomization.yaml to enable webhook and ca injection")
ExpectWithOffset(1, pluginutil.UncommentCode(
filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
"#- ../webhook", "#")).To(Succeed())
ExpectWithOffset(1, pluginutil.UncommentCode(
filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
"#- ../certmanager", "#")).To(Succeed())
ExpectWithOffset(1, pluginutil.UncommentCode(
filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
"#- ../prometheus", "#")).To(Succeed())
ExpectWithOffset(1, pluginutil.UncommentCode(
filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
"#- manager_webhook_patch.yaml", "#")).To(Succeed())
ExpectWithOffset(1, pluginutil.UncommentCode(
filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
"#- webhookcainjection_patch.yaml", "#")).To(Succeed())
ExpectWithOffset(1, pluginutil.UncommentCode(filepath.Join(kbc.Dir, "config", "default", "kustomization.yaml"),
`#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
# fieldref:
# fieldpath: metadata.namespace
#- name: CERTIFICATE_NAME
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
#- name: SERVICE_NAMESPACE # namespace of the service
# objref:
# kind: Service
# version: v1
# name: webhook-service
# fieldref:
# fieldpath: metadata.namespace
#- name: SERVICE_NAME
# objref:
# kind: Service
# version: v1
# name: webhook-service`, "#")).To(Succeed())

}
22 changes: 22 additions & 0 deletions test/e2e/v3/plugin_cluster_test.go
Expand Up @@ -136,6 +136,28 @@ var _ = Describe("kubebuilder", func() {
Run(kbc)
})
})

Context("plugin base.go.kubebuilder.io/v4-alpha", func() {
// Use cert-manager with v1 CRs.
BeforeEach(func() {
By("installing the cert-manager bundle")
Expect(kbc.InstallCertManager(false)).To(Succeed())
})
AfterEach(func() {
By("uninstalling the cert-manager bundle")
kbc.UninstallCertManager(false)
})

It("should generate a runnable project", func() {
// Skip if cluster version < 1.16, when v1 CRDs and webhooks did not exist.
if srvVer := kbc.K8sVersion.ServerVersion; srvVer.GetMajorInt() <= 1 && srvVer.GetMinorInt() < 17 {
Skip(fmt.Sprintf("cluster version %s does not support v1 CRDs or webhooks", srvVer.GitVersion))
}

GenerateV4(kbc, "v1")
Run(kbc)
})
})
})
})

Expand Down
13 changes: 9 additions & 4 deletions test/testdata/generate.sh
Expand Up @@ -45,7 +45,7 @@ function scaffold_test_project {
header_text "Initializing project ..."
$kb init $init_flags --domain testproject.org --license apache2 --owner "The Kubernetes authors"

if [ $project == "project-v2" ] || [ $project == "project-v3" ] || [ $project == "project-v3-config" ] || [ $project == "project-v3-with-kustomize-v2" ]; then
if [ $project == "project-v2" ] || [ $project == "project-v3" ] || [ $project == "project-v3-config" ] || [ $project == "project-v3-with-kustomize-v2" ] || [ $project == "project-v4" ] || [ $project == "project-v4-config" ]; then
header_text 'Creating APIs ...'
$kb create api --group crew --version v1 --kind Captain --controller=true --resource=true --make=false
$kb create api --group crew --version v1 --kind Captain --controller=true --resource=true --make=false --force
Expand All @@ -61,7 +61,7 @@ function scaffold_test_project {
fi
$kb create webhook --group crew --version v1 --kind FirstMate --conversion

if [ $project == "project-v3" ]; then
if [ $project == "project-v3" ] || [ $project == "project-v4" ]; then
$kb create api --group crew --version v1 --kind Admiral --plural=admirales --controller=true --resource=true --namespaced=false --make=false
$kb create webhook --group crew --version v1 --kind Admiral --plural=admirales --defaulting
else
Expand Down Expand Up @@ -94,11 +94,11 @@ function scaffold_test_project {
$kb create api --group foo.policy --version v1 --kind HealthCheckPolicy --controller=true --resource=true --make=false

$kb create api --group apps --version v1 --kind Deployment --controller=true --resource=false --make=false

$kb create api --group foo --version v1 --kind Bar --controller=true --resource=true --make=false
$kb create api --group fiz --version v1 --kind Bar --controller=true --resource=true --make=false

if [ $project == "project-v3-multigroup" ]; then
if [ $project == "project-v3-multigroup" ] || [ $project == "project-v4-multigroup" ]; then
$kb create api --version v1 --kind Lakers --controller=true --resource=true --make=false
$kb create webhook --version v1 --kind Lakers --defaulting --programmatic-validation
fi
Expand Down Expand Up @@ -132,3 +132,8 @@ scaffold_test_project project-v3-addon --plugins="go/v3,declarative"
scaffold_test_project project-v3-config --component-config
scaffold_test_project project-v3-v1beta1
scaffold_test_project project-v3-with-kustomize-v2 --plugins="kustomize/v2-alpha,base.go.kubebuilder.io/v3"
# Project version 4 (default) uses plugin go/v4 (default).
scaffold_test_project project-v4
scaffold_test_project project-v4-multigroup
scaffold_test_project project-v4-addon --plugins="go/v4-alpha,declarative"
scaffold_test_project project-v4-config --component-config
4 changes: 4 additions & 0 deletions testdata/project-v4-addon/.dockerignore
@@ -0,0 +1,4 @@
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/
testbin/
24 changes: 24 additions & 0 deletions testdata/project-v4-addon/.gitignore
@@ -0,0 +1,24 @@

# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Kubernetes Generated files - skip generated files, except for vendored files

!vendor/**/zz_generated.*

# editor and IDE paraphernalia
.idea
*.swp
*.swo
*~
34 changes: 34 additions & 0 deletions testdata/project-v4-addon/Dockerfile
@@ -0,0 +1,34 @@
# Build the manager binary
FROM golang:1.17 as builder

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/
# https://github.com/kubernetes-sigs/kubebuilder-declarative-pattern/blob/master/docs/addon/walkthrough/README.md#adding-a-manifest
# Stage channels and make readable
COPY channels/ /channels/
RUN chmod -R a+rx /channels/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 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
WORKDIR /
COPY --from=builder /workspace/manager .
# copy channels
COPY --from=builder /channels /channels

USER 65532:65532

ENTRYPOINT ["/manager"]
133 changes: 133 additions & 0 deletions testdata/project-v4-addon/Makefile
@@ -0,0 +1,133 @@

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

# 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

# Setting SHELL to bash allows bash commands to be executed by recipes.
# This is a requirement for 'setup-envtest.sh' in the test target.
# 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

.PHONY: all
all: build

##@ General

# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

.PHONY: help
help: ## Display this help.
@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)

##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...

.PHONY: vet
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

##@ Build

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

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

.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
docker build -t ${IMG} .

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

##@ 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 -

##@ Build Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest

## Tool Versions
KUSTOMIZE_VERSION ?= v3.8.7
CONTROLLER_TOOLS_VERSION ?= v0.8.0

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
curl -s $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN)

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)

.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

0 comments on commit 6fb7b17

Please sign in to comment.