Skip to content

Commit

Permalink
Add target and tests to distribute the project
Browse files Browse the repository at this point in the history
  • Loading branch information
camilamacedo86 committed Sep 17, 2023
1 parent e769e76 commit 77fbe31
Show file tree
Hide file tree
Showing 33 changed files with 4,431 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes

.PHONY: yamllint
yamllint:
@docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/yamllint:latest testdata -d "{extends: relaxed, rules: {line-length: {max: 120}}}" --no-warnings
@files=$$(find testdata -name '*.yaml' ! -path 'testdata/*/dist/install.yaml'); \
docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/yamllint:latest $$files -d "{extends: relaxed, rules: {line-length: {max: 120}}}" --no-warnings

GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
golangci-lint:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
- $(CONTAINER_TOOL) buildx rm project-v3-builder
rm Dockerfile.cross

.PHONY: build-installer
build-installer: manifests kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
@if [ -d "config/crd" ]; then \
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
fi
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default >> dist/install.yaml

##@ Deployment

ifndef ignore-not-found
Expand Down
19 changes: 19 additions & 0 deletions docs/book/src/component-config-tutorial/testdata/project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ UnDeploy the controller from the cluster:
make undeploy
```

## Distributing your project

Following the steps for you build the installer and to distribute this project for users.

### Build the installer
To build the installer for the image built and published in the registry:

make build-installer IMG=<some-registry>/project:tag

NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
build with Kustomize to install this project.

### To install via the installer

You must just run kubectl apply -f dist/install.yaml.
Therefore, users can install this project if they have access to the repository by running:

kubectl apply -f https://raw.githubusercontent.com/<org>/project/<tag or branch>/dist/install.yaml

## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
app.kubernetes.io/instance: manager-role
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: project
app.kubernetes.io/part-of: project
app.kubernetes.io/managed-by: kustomize
name: manager-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
9 changes: 9 additions & 0 deletions docs/book/src/cronjob-tutorial/testdata/project/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
- $(CONTAINER_TOOL) buildx rm project-v3-builder
rm Dockerfile.cross

.PHONY: build-installer
build-installer: manifests kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
@if [ -d "config/crd" ]; then \
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
fi
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default >> dist/install.yaml

##@ Deployment

ifndef ignore-not-found
Expand Down
19 changes: 19 additions & 0 deletions docs/book/src/cronjob-tutorial/testdata/project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ UnDeploy the controller from the cluster:
make undeploy
```

## Distributing your project

Following the steps for you build the installer and to distribute this project for users.

### Build the installer
To build the installer for the image built and published in the registry:

make build-installer IMG=<some-registry>/project:tag

NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
build with Kustomize to install this project.

### To install via the installer

You must just run kubectl apply -f dist/install.yaml.
Therefore, users can install this project if they have access to the repository by running:

kubectl apply -f https://raw.githubusercontent.com/<org>/project/<tag or branch>/dist/install.yaml

## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project

Expand Down
11 changes: 11 additions & 0 deletions pkg/plugins/common/kustomize/v2/scaffolds/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
pluginutil "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2/scaffolds/internal/templates/config/crd"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2/scaffolds/internal/templates/config/crd/patches"
Expand Down Expand Up @@ -72,6 +73,16 @@ func (s *apiScaffolder) Scaffold() error {

// Keep track of these values before the update
if s.resource.HasAPI() {
kustomizeFilePath := "config/default/kustomization.yaml"
err := pluginutil.UncommentCode(kustomizeFilePath, "#- ../crd", `#`)
if err != nil {
hasCRUncommented, err := pluginutil.HasFragment(kustomizeFilePath, "- ../crd")
if !hasCRUncommented || err != nil {
log.Errorf("Unable to find the target #- ../crd to uncomment in the file "+
"%s.", kustomizeFilePath)
}
}

if err := scaffold.Execute(
&samples.CRDSample{Force: s.force},
&rbac.CRDEditorRole{},
Expand Down
3 changes: 3 additions & 0 deletions pkg/plugins/common/kustomize/v2/scaffolds/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func (s *initScaffolder) Scaffold() error {
&rbac.AuthProxyService{},
&rbac.AuthProxyClientRole{},
&rbac.RoleBinding{},
// We need to create a Role because if the project
// has not CRD define the controller-gen will not generate this file
&rbac.Role{},
&rbac.LeaderElectionRole{},
&rbac.LeaderElectionRoleBinding{},
&rbac.ServiceAccount{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namePrefix: {{ .ProjectName }}-
# someName: someValue
resources:
- ../crd
#- ../crd
- ../rbac
- ../manager
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rbac

import (
"path/filepath"

"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
)

var _ machinery.Template = &Role{}

// Role scaffolds a file that defines the role for the manager
type Role struct {
machinery.TemplateMixin
machinery.ProjectNameMixin
}

// SetTemplateDefaults implements file.Template
func (f *Role) SetTemplateDefaults() error {
if f.Path == "" {
f.Path = filepath.Join("config", "rbac", "role.yaml")
}

f.TemplateBody = managerRoleTemplate

f.IfExistsAction = machinery.SkipFile

return nil
}

const managerRoleTemplate = `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
app.kubernetes.io/instance: manager-role
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: {{ .ProjectName }}
app.kubernetes.io/part-of: {{ .ProjectName }}
app.kubernetes.io/managed-by: kustomize
name: manager-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
`
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
- $(CONTAINER_TOOL) buildx rm project-v3-builder
rm Dockerfile.cross
.PHONY: build-installer
build-installer: manifests kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
@if [ -d "config/crd" ]; then \
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
fi
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default >> dist/install.yaml
##@ Deployment
ifndef ignore-not-found
Expand Down
19 changes: 19 additions & 0 deletions pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ UnDeploy the controller from the cluster:
%s
## Distributing your project
Following the steps for you build the installer and to distribute this project for users.
### Build the installer
To build the installer for the image built and published in the registry:
make build-installer IMG=<some-registry>/{{ .ProjectName }}:tag
NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
build with Kustomize to install this project.
### To install via the installer
You must just run kubectl apply -f dist/install.yaml.
Therefore, users can install this project if they have access to the repository by running:
kubectl apply -f https://raw.githubusercontent.com/<org>/{{ .ProjectName }}/<tag or branch>/dist/install.yaml
## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/v4/e2e_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
. "github.com/onsi/gomega"
)

// Run e2e tests using the Ginkgo runner.
// RunWith e2e tests using the Ginkgo runner.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
fmt.Fprintf(GinkgoWriter, "Starting kubebuilder suite\n")
Expand Down
122 changes: 122 additions & 0 deletions test/e2e/v4/plugin_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,131 @@ var _ = Describe("kubebuilder", func() {
GenerateV4(kbc)
Run(kbc)
})
It("should generate a runnable project"+
" with the Installer", func() {
GenerateV4(kbc)
RunWithInstaller(kbc)
})
})
})

// TODO: We need to clean up and refactor these tests.
// Remove duplicates and ensure cohesion and encapsulation
// For Example: Run should not have make generate and manifests it should be part of the build of the project
// Also we can encapsulate the checks such as: checkManager, checkPrometheus, checkCertManager so that we can reuse them
// when or not is required and create many scenarios.

// RunWithInstaller runs a set of e2e tests for a scaffolded project defined by a TestContext.
func RunWithInstaller(kbc *utils.TestContext) {
var controllerPodName string
var err error

By("updating the go.mod")
err = kbc.Tidy()
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("run make manifests")
err = kbc.Make("manifests")
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("run make generate")
err = kbc.Make("generate")
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("building the controller image")
err = kbc.Make("docker-build", "IMG="+kbc.ImageName)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("loading the controller docker image into the kind cluster")
err = kbc.LoadImageToKindCluster()
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("building the installer")
err = kbc.Make("build-installer", "IMG="+kbc.ImageName)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

// NOTE: If you want to run the test against a GKE cluster, you will need to grant yourself permission.
// Otherwise, you may see "... is forbidden: attempt to grant extra privileges"
// $ kubectl create clusterrolebinding myname-cluster-admin-binding \
// --clusterrole=cluster-admin --user=myname@mycompany.com
// https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control
By("deploying the controller-manager with the installer")

_, err = kbc.Kubectl.Apply(true, "-f", "dist/install.yaml")
ExpectWithOffset(1, err).NotTo(HaveOccurred())

By("validating that the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name
podOutput, err := kbc.Kubectl.Get(
true,
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}"+
"{{ \"\\n\" }}{{ end }}{{ end }}")
ExpectWithOffset(2, err).NotTo(HaveOccurred())
podNames := util.GetNonEmptyLines(podOutput)
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))

// Validate pod status
status, err := kbc.Kubectl.Get(
true,
"pods", controllerPodName, "-o", "jsonpath={.status.phase}")
ExpectWithOffset(2, err).NotTo(HaveOccurred())
if status != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
}
defer func() {
out, err := kbc.Kubectl.CommandInNamespace("describe", "all")
ExpectWithOffset(1, err).NotTo(HaveOccurred())
fmt.Fprintln(GinkgoWriter, out)
}()
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())

By("granting permissions to access the metrics")
_, err = kbc.Kubectl.Command(
"create", "clusterrolebinding", fmt.Sprintf("metrics-%s", kbc.TestSuffix),
fmt.Sprintf("--clusterrole=e2e-%s-metrics-reader", kbc.TestSuffix),
fmt.Sprintf("--serviceaccount=%s:%s", kbc.Kubectl.Namespace, kbc.Kubectl.ServiceAccount))
ExpectWithOffset(1, err).NotTo(HaveOccurred())

_ = curlMetrics(kbc)

By("validating that cert-manager has provisioned the certificate Secret")
EventuallyWithOffset(1, func() error {
_, err := kbc.Kubectl.Get(
true,
"secrets", "webhook-server-cert")
return err
}, time.Minute, time.Second).Should(Succeed())

By("validating that the Prometheus manager has provisioned the Service")
EventuallyWithOffset(1, func() error {
_, err := kbc.Kubectl.Get(
false,
"Service", "prometheus-operator")
return err
}, time.Minute, time.Second).Should(Succeed())

By("validating that the ServiceMonitor for Prometheus is applied in the namespace")
_, err = kbc.Kubectl.Get(
true,
"ServiceMonitor")
ExpectWithOffset(1, err).NotTo(HaveOccurred())

Check failure on line 206 in test/e2e/v4/plugin_cluster_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gofmt`-ed with `-s` (gofmt)
By("validating that the created resource object gets reconciled in the controller")
metricsOutput := curlMetrics(kbc)
ExpectWithOffset(1, metricsOutput).To(ContainSubstring(fmt.Sprintf(
`controller_runtime_reconcile_total{controller="%s",result="success"} 1`,
strings.ToLower(kbc.Kind),
)))
}

// Run runs a set of e2e tests for a scaffolded project defined by a TestContext.
func Run(kbc *utils.TestContext) {
var controllerPodName string
Expand Down
Loading

0 comments on commit 77fbe31

Please sign in to comment.