Skip to content

Commit 4eba8f3

Browse files
authored
Cross-component E2E for operator framework (#286)
* Added e2e for plain+v0 operator install, upgrade and delete Signed-off-by: jubittajohn <[email protected]> * Added tests to automate bundle and FBC image creation for plain bundles Signed-off-by: jubittajohn <[email protected]> * Added error messages for each failed assertion; Added comments and README Signed-off-by: jubittajohn <[email protected]> * Added operator-sdk support to the e2e workflow Signed-off-by: jubittajohn <[email protected]> Refractored the plain bundle and registry bundle interactions; Updated the comments and README Signed-off-by: jubittajohn <[email protected]> Added make target to install operator-sdk; Added make target to deploy a local registry server; Changed test to use the local registry server Signed-off-by: jubittajohn <[email protected]> * Modified adding opm and operator-sdk binary using bingo; Updated files to be consistent in styling Signed-off-by: jubittajohn <[email protected]> * Updated to generate plain manifests from an SDK project with kustomize;Restructured code to have a single It block in a describe block; Signed-off-by: jubittajohn <[email protected]> Combined local-registry cleanup make target; Added support for container runtime in consideration Signed-off-by: jubittajohn <[email protected]> Bumped the upgrade version from 0.1.1 to 0.2.0 Signed-off-by: jubittajohn <[email protected]> Updated comments and README Signed-off-by: jubittajohn <[email protected]> --------- Signed-off-by: jubittajohn <[email protected]>
1 parent 28da6bd commit 4eba8f3

14 files changed

+4145
-2
lines changed

.bingo/Variables.mk

+12
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ $(KUSTOMIZE): $(BINGO_DIR)/kustomize.mod
5959
@echo "(re)installing $(GOBIN)/kustomize-v4.5.7"
6060
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=kustomize.mod -o=$(GOBIN)/kustomize-v4.5.7 "sigs.k8s.io/kustomize/kustomize/v4"
6161

62+
OPERATOR_SDK := $(GOBIN)/operator-sdk-v1.31.0
63+
$(OPERATOR_SDK): $(BINGO_DIR)/operator-sdk.mod
64+
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
65+
@echo "(re)installing $(GOBIN)/operator-sdk-v1.31.0"
66+
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -ldflags=-X=github.com/operator-framework/operator-sdk/internal/version.Version=v1.31.0 -mod=mod -modfile=operator-sdk.mod -o=$(GOBIN)/operator-sdk-v1.31.0 "github.com/operator-framework/operator-sdk/cmd/operator-sdk"
67+
68+
OPM := $(GOBIN)/opm-v1.28.0
69+
$(OPM): $(BINGO_DIR)/opm.mod
70+
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
71+
@echo "(re)installing $(GOBIN)/opm-v1.28.0"
72+
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=opm.mod -o=$(GOBIN)/opm-v1.28.0 "github.com/operator-framework/operator-registry/cmd/opm"
73+
6274
SETUP_ENVTEST := $(GOBIN)/setup-envtest-v0.0.0-20230606045100-e54088c8c7da
6375
$(SETUP_ENVTEST): $(BINGO_DIR)/setup-envtest.mod
6476
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.

.bingo/operator-sdk.mod

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
2+
3+
go 1.20
4+
5+
replace github.com/containerd/containerd => github.com/containerd/containerd v1.4.11
6+
7+
replace github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
8+
9+
replace github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.10.0
10+
11+
require github.com/operator-framework/operator-sdk v1.31.0 // cmd/operator-sdk -ldflags=-X=github.com/operator-framework/operator-sdk/internal/version.Version=v1.31.0

.bingo/operator-sdk.sum

+1,590
Large diffs are not rendered by default.

.bingo/opm.mod

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
2+
3+
go 1.20
4+
5+
replace github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
6+
7+
require github.com/operator-framework/operator-registry v1.28.0 // cmd/opm

.bingo/opm.sum

+947
Large diffs are not rendered by default.

.bingo/variables.env

+4
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@ KIND="${GOBIN}/kind-v0.15.0"
2222

2323
KUSTOMIZE="${GOBIN}/kustomize-v4.5.7"
2424

25+
OPERATOR_SDK="${GOBIN}/operator-sdk-v1.31.0"
26+
27+
OPM="${GOBIN}/opm-v1.28.0"
28+
2529
SETUP_ENVTEST="${GOBIN}/setup-envtest-v0.0.0-20230606045100-e54088c8c7da"
2630

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: operator-developer-e2e
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
push:
7+
branches:
8+
- main
9+
10+
jobs:
11+
operator-developer-e2e:
12+
runs-on: ubuntu-latest
13+
steps:
14+
15+
- uses: actions/checkout@v3
16+
17+
- uses: actions/setup-go@v4
18+
with:
19+
go-version-file: go.mod
20+
21+
- name: Run the operator framework e2e test
22+
run: |
23+
make operator-developer-e2e

Makefile

+26
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ E2E_FLAGS ?= ""
9999
test-e2e: $(GINKGO) ## Run the e2e tests
100100
$(GINKGO) --tags $(GO_BUILD_TAGS) $(E2E_FLAGS) -trace -progress $(FOCUS) test/e2e
101101

102+
.PHONY: test-op-dev-e2e
103+
test-op-dev-e2e: $(GINKGO) ## Run operator create, upgrade and delete tests
104+
CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) $(GINKGO) --tags $(GO_BUILD_TAGS) $(E2E_FLAGS) -trace -progress $(FOCUS) test/operator-framework-e2e
105+
102106
.PHONY: test-unit
103107
ENVTEST_VERSION = $(shell go list -m k8s.io/client-go | cut -d" " -f2 | sed 's/^v0\.\([[:digit:]]\{1,\}\)\.[[:digit:]]\{1,\}$$/1.\1.x/')
104108
UNIT_TEST_DIRS=$(shell go list ./... | grep -v /test/)
@@ -111,6 +115,10 @@ e2e: KUSTOMIZE_BUILD_DIR=config/e2e
111115
e2e: GO_BUILD_FLAGS=-cover
112116
e2e: run kind-load-test-artifacts test-e2e e2e-coverage kind-cluster-cleanup ## Run e2e test suite on local kind cluster
113117

118+
.PHONY: operator-developer-e2e
119+
operator-developer-e2e: KIND_CLUSTER_NAME=operator-controller-op-dev-e2e ## Run operator-developer e2e on local kind cluster
120+
operator-developer-e2e: run $(OPM) $(OPERATOR_SDK) $(KUSTOMIZE) deploy-local-registry test-op-dev-e2e cleanup-local-registry kind-cluster-cleanup
121+
114122
.PHONY: e2e-coverage
115123
e2e-coverage:
116124
COVERAGE_OUTPUT=./e2e-cover.out ./hack/e2e-coverage.sh
@@ -141,6 +149,24 @@ kind-load-test-artifacts: $(KIND) ## Load the e2e testdata container images into
141149
$(KIND) load docker-image localhost/testdata/bundles/plain-v0/plain:v0.1.0 --name $(KIND_CLUSTER_NAME)
142150
$(KIND) load docker-image localhost/testdata/catalogs/test-catalog:e2e --name $(KIND_CLUSTER_NAME)
143151

152+
.PHONY: deploy-local-registry
153+
deploy-local-registry: ## Deploy local registry
154+
$(CONTAINER_RUNTIME) run -d -p 5001:5000 --restart=always --name local-registry registry:2
155+
156+
.PHONY: cleanup-local-registry
157+
cleanup-local-registry: ## Stop and remove local registry
158+
$(CONTAINER_RUNTIME) container stop local-registry
159+
$(CONTAINER_RUNTIME) container rm -v local-registry
160+
161+
opm: $(OPM)
162+
$(OPM) $(OPM_ARGS)
163+
164+
operator-sdk: $(OPERATOR_SDK)
165+
(cd $(OPERATOR_SDK_PROJECT_PATH) && $(OPERATOR_SDK) $(OPERATOR_SDK_ARGS))
166+
167+
kustomize: $(KUSTOMIZE)
168+
(cd $(OPERATOR_SDK_PROJECT_PATH) && $(KUSTOMIZE) $(KUSTOMIZE_ARGS))
169+
144170
##@ Build
145171

146172
export VERSION ?= $(shell git describe --tags --always --dirty)

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ require (
77
github.com/go-logr/logr v1.2.4
88
github.com/onsi/ginkgo/v2 v2.11.0
99
github.com/onsi/gomega v1.27.10
10+
github.com/operator-framework/api v0.17.4-0.20230223191600-0131a6301e42
1011
github.com/operator-framework/catalogd v0.4.1
1112
github.com/operator-framework/deppy v0.0.0-20230629133131-bb7b6ae7b266
1213
github.com/operator-framework/operator-registry v1.27.1
1314
github.com/operator-framework/rukpak v0.13.0
1415
github.com/spf13/pflag v1.0.5
1516
github.com/stretchr/testify v1.8.4
1617
go.uber.org/zap v1.25.0
18+
k8s.io/apiextensions-apiserver v0.26.1
1719
k8s.io/apimachinery v0.26.1
1820
k8s.io/client-go v0.26.1
1921
k8s.io/component-base v0.26.1
@@ -94,7 +96,6 @@ require (
9496
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
9597
github.com/opencontainers/go-digest v1.0.0 // indirect
9698
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
97-
github.com/operator-framework/api v0.17.4-0.20230223191600-0131a6301e42 // indirect
9899
github.com/otiai10/copy v1.2.0 // indirect
99100
github.com/pkg/errors v0.9.1 // indirect
100101
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -135,7 +136,6 @@ require (
135136
gopkg.in/yaml.v2 v2.4.0 // indirect
136137
gopkg.in/yaml.v3 v3.0.1 // indirect
137138
k8s.io/api v0.26.1 // indirect
138-
k8s.io/apiextensions-apiserver v0.26.1 // indirect
139139
k8s.io/apiserver v0.26.1 // indirect
140140
k8s.io/klog/v2 v2.80.1 // indirect
141141
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect

test/operator-framework-e2e/README.md

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Cross-component E2E for operator framework
2+
3+
This is a cross-component demo with all OLM v1 repositories. The ginkgo test does the following:
4+
- Uses operator-sdk and kustomize to build `plain+v0` bundles and create catalogs to include the bundles.
5+
- Installs, upgrades and deletes a `plain+v0` operator.
6+
- Uses operator-sdk to build `registry+v1` bundles and create catalogs to include the bundles.
7+
- Installs, upgrades and deletes a `registry+v1` operator.
8+
9+
The steps in the ginkgo test can be summarized as follows:
10+
11+
1. start with an empty directory
12+
2. call operator-sdk to initialize and generate an operator
13+
3. generate a bundle directory
14+
4. build/push/kind load bundle images from the bundle directories
15+
5. repeat steps 2-4 as necessary to get bundles for multiple operator versions
16+
6. generate a catalog directory
17+
7. build/push/kind load the catalog
18+
8. create a Catalog CR (with kubectl operator)
19+
9. create an Operator CR (with kubectl operator)
20+
10. trigger Operator upgrades (with kubectl operator)
21+
11. delete the Operator CR (with kubectl operator)
22+
12. delete the Catalog CR (with kubectl operator)
23+
13. repeat steps 2-12 for each bundle format (e.g. registry+v1 and plain+v0)
24+
## Objective
25+
- Development on OLM v1 is split across multiple repositories, and the list of relevant repositories may grow over time. While we have demos showing improvements in functionality of components over time, it can be difficult to have a picture of the state of OLM v1 at any given time for someone not following its development closely. Having a single source to look for OLM v1 behavior can provide more clarity about the state of the project.
26+
- With the scale of the OLM v1 project, it is useful to have a means to test components in the operator development + lifecycle pipeline together to create a more cohesive experience for all users.
27+
28+
## Getting Started
29+
- This test currently only works with the container runtime `docker`.
30+
- Building operator-controller, deploying it into the cluster and rest of the configuration is done in the `MakeFile` of this repo under the target `operator-developer-e2e`. This includes:
31+
32+
- Setting up a kind cluster named `operator-controller-op-dev-e2e`.
33+
- Installing the operator controller onto the cluster.
34+
- Setting up `opm`, `operator-sdk` and `kustomize` using bingo.
35+
- Setting up a local registry server for building and loading images.
36+
### Input Values used
37+
38+
Below are the input values used in the test which is specified in the `operator_framework_test.go`.
39+
40+
- The following structs defined are required, to accept input for both `plain+v0` and `registry+v1` bundles:
41+
- For getting bundle related inputs:
42+
```
43+
type BundleInfo struct {
44+
baseFolderPath string
45+
bundles []BundleContent
46+
}
47+
48+
type BundleContent struct {
49+
bInputDir string
50+
bundleVersion string
51+
imageRef string
52+
}
53+
```
54+
- `baseFolderPath` - Base/root path of the folder where the specific bundle type input data is stored.[root path to plain-v0 or registry-v1 bundles testdata]
55+
- `bundles` - Stores the data relevant to different versions of the bundle.
56+
- `bInputDir` - The directory that stores the specific version of the bundle data. The name of the directory is formed and is of the format `<operatorName>.v<bundleVersion>`.
57+
- `bundleVersion` - The specific version of the bundle data.
58+
- `imageRef` - This is formed. Stores the bundle image reference which will be of the format `<registry_repo>/< operatorName>-bundle:v.<bundleVersion>`
59+
- For getting catalog related inputs:
60+
```
61+
type CatalogDInfo struct {
62+
baseFolderPath string
63+
catalogDir string
64+
operatorName string
65+
desiredChannelName string
66+
imageRef string
67+
fbcFileName string
68+
}
69+
```
70+
- `baseFolderPath` - Base/root path of the folder that stores the catalogs.
71+
- `operatorName` - Name of the operator to be installed from the bundles.
72+
- `desiredChannelName` - Desired channel name for the operator.
73+
- `catalogDir` - This is formed. The directory to store the catalog/FBC. The directory name will be of the format: `<operator-name>-catalog`
74+
- `imageRef` - This is formed. Stores the FBC image reference which will be of the format: `<registry_repo>/<catalogDir>:test`
75+
- `fbcFileName` - Name of the FBC file. This is hard-coded as `catalog.yaml`.
76+
- For getting information related to the install/upgrade action for operators:
77+
```
78+
type OperatorActionInfo struct {
79+
installVersion string
80+
upgradeVersion string
81+
}
82+
```
83+
- `installVersion` - Version of the operator to be installed on the cluster.
84+
- `upgradeVersion` - Version of the operator to be upgraded on the cluster.
85+
86+
- The below inputs are used to form the bundle using operator-sdk.
87+
88+
```
89+
type SdkProjectInfo struct {
90+
projectName string
91+
domainName string
92+
group string
93+
version string
94+
kind string
95+
}
96+
```
97+
## How to run
98+
- Makefile target `operator-developer-e2e` : Runs the entire E2E setup.
99+
- Makefile target `test-op-dev-e2e`: Runs the ginkgo test.
100+
- Makefile target `deploy-local-registry`: Deploys local registry
101+
- Makefile target `cleanup-local-registry` : Stops and removes local registry
102+
- Makefile target `kind-cluster-cleanup`: Deletes the kind cluster
103+
104+
## Bundle Types
105+
### Plain bundles
106+
- The `plain+v0` bundles are formed using `operator-sdk` and `kustomize`.
107+
- The `kustomize` organizes the different resources present in the `operator-sdk` project into a single yaml file.
108+
- The Dockerfile for the bundle is named `plainbundle.Dockerfile` and is generated using a custom routine.
109+
- The generated bundle is stored in the format:
110+
```
111+
plain-v0
112+
└── <operatorName>.v<bundleVersion>
113+
└── manifests
114+
│ └── mainfest.yaml
115+
└── plainbundle.Dockerfile
116+
```
117+
118+
119+
- The FBC template is formed by a custom routine by using the operatorName, desiredChannelName, bundle imageRefs and bundleVersions.
120+
- `Default channel` is not used in forming the FBC as it is not an OLMv1 concept.
121+
- Only one `olm.channel` is generated which is the given <desiredChannelName>.
122+
- Upgrade graph is formed with only replaces edge.
123+
- The generated FBC is not validated using `opm` as the tool has no support for plain bundles.
124+
- The Dockerfile for the catalog is named `<operator-name>-catalog.Dockerfile` and is generated using a custom routine.
125+
- The generated catalog is stored in the format:
126+
```
127+
catalogs
128+
└── <operator-name>-catalog
129+
│ └── catalog.yaml
130+
└── <operator-name>-catalog.Dockerfile
131+
```
132+
- The catalog CR is then formed with the name `<operatorName>-catalog`.
133+
134+
- The operator is then installed and has the name `<operatorName>`.
135+
136+
### Registry Bundles
137+
138+
- The registry+v1 bundles are formed using operator-sdk.
139+
- The generated CSV uses the default values.
140+
- The bundle content is formed within the operator-sdk project directory in the folder `bundle`. This is moved to the bundle directory folder.
141+
- The generated Dockerfile has the name `bundle.Dockerfile`. The Dockerfile and bundle structure is genearted by the `operator-sdk` tool.
142+
- The generated bundle is stored in the format:
143+
```
144+
registry-v1
145+
└── <operatorName>.v<bundleVersion>
146+
└── manifests
147+
└── metadata
148+
└── bundle.Dockerfile
149+
```
150+
151+
- The FBC is formed using `opm alpha render-template semver` tool.
152+
- The semver template named `registry-semver.yaml` is formed using a custom routine by passing the bundle imageRefs.
153+
- `generatemajorchannels` and `generateminorchannels` is set to false in the semver template.
154+
- The generated catalog is stored in the format:
155+
```
156+
catalogs
157+
└── <operator-name>-catalog
158+
│ └── catalog.yaml
159+
└── <operator-name>-catalog.Dockerfile
160+
```
161+
162+
- The catalog resource is then formed with the name `<operatorName>-catalog`.
163+
164+
- The operator is then installed and has the name `<operatorName>`.
165+
166+
167+
- After the e2e workflow, all the files formed are cleared.
168+
169+
170+
## To-do
171+
1. The resources are read from input manifests using universal decoder from `k8s.io/apimachinery/pkg/runtime/serializer`.
172+
- However, in cases where a single file contains multiple YAML documents separated by `---,` the `UniversalDecoder` recognizes only the first resource. This situation is relevant as for `plain+v0` bundles generated through `kustomize,` the manifest has multiple YAML documents are combined into one file using --- separators. This is now handled by splitting the content of the YAML file and decoding each of them using the `UniversalDecoder`.
173+
- This workaround can be improved using `YAMLToJSONDecoder` from `k8s.io/apimachinery/pkg/util/yaml`. And the kind, api version and name can be get by decoding into `Unstructured` from `k8s.io/apimachinery/pkg/apis/meta/v1/unstructured`.
174+
2. All the tests pass and the operator is installed successfully. The bundledeployment succeeds and the resources are created. But the pod for the new operator failes due to `ImagePullBackOff`.
175+
- This is because the `Deployment` controller-manager uses the image `controller:latest` which is not present on the cluster.
176+
- The solution would be to replace `controller:latest` with the `busybox:latest` and then pulling and loading `busybox:latest` onto cluster.
177+
- The replacement could possibly be achieved by adding the following to `config/default/kustomization.yaml` under `operator-sdk` project:
178+
```
179+
images:
180+
- name: controller
181+
newName: controller
182+
newTag: latest
183+
```
184+
## Issues
185+
1. This test currently only works with the container runtime `docker`.
186+
- The default value of CONTAINER_RUNTIME defined in the Makefile is `docker`. Therefore the correct runtime has to be assigned to the variable `CONTAINER_RUNTIME` before calling the make target if docker is what is not being used. The test routine also assumes the runtime as `docker` if it is unable to retrieve the value of the environment variable.
187+
- But this is only a partial fix to the problem. With this change the test for `plain+v0` bundles will pass but for `registry+v1` will fail for other container runtimes. This is because `registry+v1` uses `operator-sdk` support. Thus to mimic the user experience, the targets `bundle-build` and `bundle-push` from the generated Makefile by operator-sdk tool, which has docker being hard coded as the container runtime, is used to build and push the bundle images. This could be marked as an issue and addressed when hard coding docker as container runtime in the generated Makefile is addressed by operator-sdk.
188+
189+
2. The `opm`,`operator-sdk` and `kustomize` binaries are added in operator-controller using `bingo`.
190+
- But based on discussions, if required test should be changed so that it has `opm` and `operator-sdk` in `PATH` and simply runs it like `exec.Command("opm", ...)`.
191+
- This will enable in running [a matrix](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs) for the tests and to use different versions of `opm` and `operator-sdk`.
192+
- This might help in emulating the user experience better.
193+
194+
## Tooling gaps
195+
196+
Following are the tooling gaps identified while testing `operator-framework` end-to-end:
197+
- `opm` doesn't have plain bundle support.
198+
- No tool for forming FBC for plain bundles.
199+
- No tool for generating Dockerfile for plain bundles.
200+
- No tool for generating Dockerfile for plain catalogs.
201+
- Since `opm` doesn't have plain bundle support, there is no means to validate the FBC generated for plain bundles.
202+

0 commit comments

Comments
 (0)