Skip to content

Commit cab885b

Browse files
committed
Added tests to automate bundle and FBC image creation for plain bundles
Signed-off-by: jubittajohn <[email protected]>
1 parent fabd290 commit cab885b

File tree

11 files changed

+444
-317
lines changed

11 files changed

+444
-317
lines changed

Makefile

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ e2e: KIND_CLUSTER_NAME=operator-controller-e2e
109109
e2e: run kind-load-test-artifacts test-e2e kind-cluster-cleanup ## Run e2e test suite on local kind cluster
110110

111111
operator-framework-e2e: KIND_CLUSTER_NAME=operator-controller-e2e ## Run operator-framework e2e on local kind cluster
112-
operator-framework-e2e: run kind-load-test-artifacts kind-load-test-artifacts-e2e test-operator-framework-e2e kind-cluster-cleanup
112+
operator-framework-e2e: run opm test-operator-framework-e2e kind-cluster-cleanup
113113

114114
kind-load: $(KIND) ## Loads the currently constructed image onto the cluster
115115
$(KIND) load docker-image $(IMG) --name $(KIND_CLUSTER_NAME)
@@ -129,11 +129,24 @@ kind-load-test-artifacts: $(KIND) ## Load the e2e testdata container images into
129129
$(KIND) load docker-image localhost/testdata/bundles/plain-v0/plain:v0.1.0 --name $(KIND_CLUSTER_NAME)
130130
$(KIND) load docker-image localhost/testdata/catalogs/test-catalog:e2e --name $(KIND_CLUSTER_NAME)
131131

132-
kind-load-test-artifacts-e2e: $(KIND) ## Load the operator-framework e2e testdata container images into a kind cluster
133-
$(CONTAINER_RUNTIME) build $(TESTDATA_DIR)/bundles/plain-v0/plain.v0.1.1 -t localhost/testdata/bundles/plain-v0/plain:v0.1.1
134-
$(CONTAINER_RUNTIME) build $(TESTDATA_DIR)/catalogs -f $(TESTDATA_DIR)/catalogs/plainv0-test-catalog.Dockerfile -t localhost/testdata/catalogs/plainv0-test-catalog:e2e
135-
$(KIND) load docker-image localhost/testdata/bundles/plain-v0/plain:v0.1.1 --name $(KIND_CLUSTER_NAME)
136-
$(KIND) load docker-image localhost/testdata/catalogs/plainv0-test-catalog:e2e --name $(KIND_CLUSTER_NAME)
132+
.PHONY: opm
133+
OPM = ./bin/opm
134+
OPM_VERSION = v1.28.0
135+
opm: ## Download opm locally if necessary.
136+
ifeq (,$(wildcard $(OPM)))
137+
ifeq (,$(shell which opm 2>/dev/null))
138+
@{ \
139+
set -e ;\
140+
mkdir -p $(dir $(OPM)) ;\
141+
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
142+
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/$(OPM_VERSION)/$${OS}-$${ARCH}-opm ;\
143+
chmod +x $(OPM) ;\
144+
}
145+
else
146+
OPM = $(shell which opm)
147+
endif
148+
endif
149+
137150
##@ Build
138151

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

go.mod

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ require (
1919
k8s.io/component-base v0.26.1
2020
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
2121
sigs.k8s.io/controller-runtime v0.14.4
22+
sigs.k8s.io/yaml v1.3.0
2223
)
2324

2425
require (
@@ -71,8 +72,6 @@ require (
7172
github.com/google/gofuzz v1.2.0 // indirect
7273
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
7374
github.com/google/uuid v1.3.0 // indirect
74-
github.com/gorilla/mux v1.8.0 // indirect
75-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
7675
github.com/h2non/filetype v1.1.1 // indirect
7776
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect
7877
github.com/imdario/mergo v0.3.13 // indirect
@@ -92,10 +91,7 @@ require (
9291
github.com/modern-go/reflect2 v1.0.2 // indirect
9392
github.com/morikuni/aec v1.0.0 // indirect
9493
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
95-
github.com/opencontainers/go-digest v1.0.0 // indirect
96-
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
97-
github.com/operator-framework/api v0.17.4-0.20230223191600-0131a6301e42 // indirect
98-
github.com/otiai10/copy v1.2.0 // indirect
94+
github.com/operator-framework/api v0.17.3 // indirect
9995
github.com/pkg/errors v0.9.1 // indirect
10096
github.com/pmezard/go-difflib v1.0.0 // indirect
10197
github.com/prometheus/client_golang v1.14.0 // indirect
@@ -144,5 +140,4 @@ require (
144140
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35 // indirect
145141
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
146142
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
147-
sigs.k8s.io/yaml v1.3.0 // indirect
148143
)

go.sum

Lines changed: 10 additions & 245 deletions
Large diffs are not rendered by default.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
schema: catalog-config
2+
packageName: plain
3+
channelData:
4+
- channelName: beta
5+
channelEntries:
6+
- entryVersion: 0.1.0
7+
replaces: null
8+
skips:
9+
- 0.1.1
10+
skipRange: null
11+
- entryVersion: 0.1.1
12+
replaces: 0.1.0
13+
skips:
14+
- null
15+
skipRange: null
16+
- channelName: foo
17+
channelEntries:
18+
- entryVersion: 0.1.0
19+
replaces: null
20+
skips:
21+
- null
22+
skipRange: null
23+
- entryVersion: 0.1.1
24+
replaces: 0.1.0
25+
skips:
26+
- null
27+
skipRange: null
28+
bundleData:
29+
- bundleImage: localhost/testdata/bundles/plain-v0/plain:v0.1.0
30+
bundleVersion: 0.1.0
31+
- bundleImage: localhost/testdata/bundles/plain-v0/plain:v0.1.1
32+
bundleVersion: 0.1.1
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
8+
"sigs.k8s.io/yaml"
9+
)
10+
11+
const (
12+
schemaName = "catalog-config"
13+
)
14+
15+
type ChannelEntry struct {
16+
EntryVersion string `json:"entryVersion"`
17+
Replaces string `json:"replaces,omitempty"`
18+
Skips []string `json:"skips,omitempty"`
19+
SkipRange string `json:"skipRange,omitempty"`
20+
}
21+
22+
type ChannelData struct {
23+
ChannelName string `json:"channelName"`
24+
ChannelEntries []ChannelEntry `json:"channelEntries"`
25+
}
26+
27+
type BundleData struct {
28+
BundleImage string `json:"bundleImage"`
29+
BundleVersion string `json:"bundleVersion"`
30+
}
31+
32+
type Config struct {
33+
Schema string `json:"schema"`
34+
PackageName string `json:"packageName"`
35+
ChannelData []ChannelData `json:"channelData"`
36+
BundleData []BundleData `json:"bundleData"`
37+
}
38+
39+
func ReadFile(f string) (*Config, error) {
40+
b, err := readFile(f)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
var c Config
46+
err = yaml.Unmarshal(b, &c)
47+
if err != nil {
48+
return nil, err
49+
}
50+
if c.Schema != schemaName {
51+
return nil, fmt.Errorf("invalid schema: %q should be %q: %v", c.Schema, schemaName, err)
52+
}
53+
if c.PackageName == "" {
54+
return nil, errors.New("missing required package name")
55+
}
56+
if len(c.ChannelData) == 0 {
57+
return nil, errors.New("missing required channel information")
58+
}
59+
if len(c.BundleData) == 0 {
60+
return nil, errors.New("missing required bundle information")
61+
}
62+
63+
return &c, nil
64+
}
65+
66+
// overrideable func for mocking os.ReadFile
67+
var readFile = func(file string) ([]byte, error) {
68+
return os.ReadFile(file)
69+
}

test/operator-e2e/create_fbc.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package operatore2e
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"os"
8+
9+
"github.com/operator-framework/operator-registry/alpha/declcfg"
10+
"github.com/operator-framework/operator-registry/alpha/property"
11+
12+
"github.com/operator-framework/operator-controller/test/operator-e2e/config"
13+
)
14+
15+
const (
16+
SchemaPackage = "olm.package"
17+
SchemaChannel = "olm.channel"
18+
SchemaBundle = "olm.bundle"
19+
SchemaBundleMediatype = "olm.bundle.mediatype"
20+
BundleMediatype = "plain+v0"
21+
)
22+
23+
func CreateFBC(configFilePath string) (*declcfg.DeclarativeConfig, error) {
24+
config, err := config.ReadFile(configFilePath)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
dPackage := formPackage(*config)
30+
dChannel := formChannel(*config)
31+
dBundle := formBundle(*config)
32+
33+
fbc := declcfg.DeclarativeConfig{
34+
Packages: []declcfg.Package{dPackage},
35+
Channels: dChannel,
36+
Bundles: dBundle,
37+
}
38+
return &fbc, nil
39+
}
40+
41+
func formPackage(config config.Config) declcfg.Package {
42+
packageFormed := declcfg.Package{
43+
Schema: SchemaPackage,
44+
Name: config.PackageName,
45+
DefaultChannel: config.ChannelData[0].ChannelName,
46+
}
47+
return packageFormed
48+
}
49+
50+
func formChannel(config config.Config) []declcfg.Channel {
51+
channelFormed := make([]declcfg.Channel, 0, len(config.ChannelData))
52+
for _, channel := range config.ChannelData {
53+
channelEntries := formChannelEntries(config.PackageName, channel)
54+
channelFormed = append(channelFormed, declcfg.Channel{
55+
Schema: SchemaChannel,
56+
Name: channel.ChannelName,
57+
Package: config.PackageName,
58+
Entries: channelEntries,
59+
})
60+
}
61+
return channelFormed
62+
}
63+
64+
func formChannelEntries(pkgName string, channel config.ChannelData) []declcfg.ChannelEntry {
65+
channelEntries := make([]declcfg.ChannelEntry, 0, len(channel.ChannelEntries))
66+
for _, channelEntry := range channel.ChannelEntries {
67+
replace := ""
68+
if channelEntry.Replaces != "" {
69+
replace = pkgName + "." + channelEntry.Replaces
70+
}
71+
72+
skip := []string{}
73+
if len(channelEntry.Skips) != 0 {
74+
for _, s := range channelEntry.Skips {
75+
if s != "" {
76+
skip = append(skip, s)
77+
}
78+
}
79+
}
80+
channelEntries = append(channelEntries, declcfg.ChannelEntry{
81+
Name: pkgName + "." + channelEntry.EntryVersion,
82+
Replaces: replace,
83+
Skips: skip,
84+
SkipRange: channelEntry.SkipRange,
85+
})
86+
}
87+
return channelEntries
88+
}
89+
90+
func formBundle(config config.Config) []declcfg.Bundle {
91+
bundleFormed := make([]declcfg.Bundle, 0, len(config.BundleData))
92+
for _, bundle := range config.BundleData {
93+
var properties []property.Property
94+
properties = append(properties, property.Property{
95+
Type: SchemaPackage,
96+
Value: json.RawMessage(fmt.Sprintf(`{"packageName": "%s", "version": "%s"}`, config.PackageName, bundle.BundleVersion)),
97+
})
98+
properties = append(properties, property.Property{
99+
Type: SchemaBundleMediatype,
100+
Value: json.RawMessage(fmt.Sprintf(`"%s"`, BundleMediatype)),
101+
})
102+
103+
bundleFormed = append(bundleFormed, declcfg.Bundle{
104+
Schema: SchemaBundle,
105+
Name: config.PackageName + "." + bundle.BundleVersion,
106+
Package: config.PackageName,
107+
Image: bundle.BundleImage,
108+
Properties: properties,
109+
})
110+
}
111+
return bundleFormed
112+
}
113+
114+
func WriteFBC(fbc declcfg.DeclarativeConfig, fbcFilePath string, fbcFileName string) error {
115+
var buf bytes.Buffer
116+
err := declcfg.WriteYAML(fbc, &buf)
117+
if err != nil {
118+
return err
119+
}
120+
121+
_, err = os.Stat(fbcFilePath)
122+
if os.IsNotExist(err) {
123+
err := os.MkdirAll(fbcFilePath, 0755)
124+
if err != nil {
125+
fmt.Printf("Failed to create directory: %v\n", err)
126+
return err
127+
}
128+
}
129+
file, err := os.Create(fbcFilePath + "/" + fbcFileName)
130+
if err != nil {
131+
fmt.Printf("Failed to create file: %v\n", err)
132+
return err
133+
}
134+
defer file.Close()
135+
136+
err = os.WriteFile(fbcFilePath+"/"+fbcFileName, buf.Bytes(), 0600)
137+
if err != nil {
138+
return err
139+
}
140+
141+
return nil
142+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package operatore2e
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"text/template"
7+
)
8+
9+
func generateDockerFile(dockerFilePath string, yamlFolderName string, dockerFileName string) error {
10+
t, err := template.New("dockerfile").Parse(dockerfileTmpl)
11+
if err != nil {
12+
panic(err)
13+
}
14+
15+
dockerFilePath = filepath.Join(dockerFilePath, dockerFileName)
16+
file, err := os.Create(dockerFilePath)
17+
if err != nil {
18+
return err
19+
}
20+
defer file.Close()
21+
22+
_, err = file.WriteString("FROM scratch\n")
23+
if err != nil {
24+
return err
25+
}
26+
err = t.Execute(file, struct{ YamlDir string }{yamlFolderName})
27+
if err != nil {
28+
return err
29+
}
30+
31+
return nil
32+
}
33+
34+
const dockerfileTmpl = `ADD {{.YamlDir}} /configs/{{.YamlDir}}
35+
`

0 commit comments

Comments
 (0)