Skip to content

Commit

Permalink
Added tests to automate bundle and FBC image creation for plain bundles
Browse files Browse the repository at this point in the history
Signed-off-by: jubittajohn <jujohn@redhat.com>
  • Loading branch information
jubittajohn committed Jul 27, 2023
1 parent fabd290 commit cab885b
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 317 deletions.
25 changes: 19 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ e2e: KIND_CLUSTER_NAME=operator-controller-e2e
e2e: run kind-load-test-artifacts test-e2e kind-cluster-cleanup ## Run e2e test suite on local kind cluster

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

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

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

##@ Build

export VERSION ?= $(shell git describe --tags --always --dirty)
Expand Down
9 changes: 2 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
k8s.io/component-base v0.26.1
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
sigs.k8s.io/controller-runtime v0.14.4
sigs.k8s.io/yaml v1.3.0
)

require (
Expand Down Expand Up @@ -71,8 +72,6 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/h2non/filetype v1.1.1 // indirect
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect
github.com/imdario/mergo v0.3.13 // indirect
Expand All @@ -92,10 +91,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/operator-framework/api v0.17.4-0.20230223191600-0131a6301e42 // indirect
github.com/otiai10/copy v1.2.0 // indirect
github.com/operator-framework/api v0.17.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
Expand Down Expand Up @@ -144,5 +140,4 @@ require (
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
255 changes: 10 additions & 245 deletions go.sum

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions test/operator-e2e/config/catalog_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
schema: catalog-config
packageName: plain
channelData:
- channelName: beta
channelEntries:
- entryVersion: 0.1.0
replaces: null
skips:
- 0.1.1
skipRange: null
- entryVersion: 0.1.1
replaces: 0.1.0
skips:
- null
skipRange: null
- channelName: foo
channelEntries:
- entryVersion: 0.1.0
replaces: null
skips:
- null
skipRange: null
- entryVersion: 0.1.1
replaces: 0.1.0
skips:
- null
skipRange: null
bundleData:
- bundleImage: localhost/testdata/bundles/plain-v0/plain:v0.1.0
bundleVersion: 0.1.0
- bundleImage: localhost/testdata/bundles/plain-v0/plain:v0.1.1
bundleVersion: 0.1.1
69 changes: 69 additions & 0 deletions test/operator-e2e/config/read_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package config

import (
"errors"
"fmt"
"os"

"sigs.k8s.io/yaml"
)

const (
schemaName = "catalog-config"
)

type ChannelEntry struct {
EntryVersion string `json:"entryVersion"`
Replaces string `json:"replaces,omitempty"`
Skips []string `json:"skips,omitempty"`
SkipRange string `json:"skipRange,omitempty"`
}

type ChannelData struct {
ChannelName string `json:"channelName"`
ChannelEntries []ChannelEntry `json:"channelEntries"`
}

type BundleData struct {
BundleImage string `json:"bundleImage"`
BundleVersion string `json:"bundleVersion"`
}

type Config struct {
Schema string `json:"schema"`
PackageName string `json:"packageName"`
ChannelData []ChannelData `json:"channelData"`
BundleData []BundleData `json:"bundleData"`
}

func ReadFile(f string) (*Config, error) {
b, err := readFile(f)
if err != nil {
return nil, err
}

var c Config
err = yaml.Unmarshal(b, &c)
if err != nil {
return nil, err
}
if c.Schema != schemaName {
return nil, fmt.Errorf("invalid schema: %q should be %q: %v", c.Schema, schemaName, err)
}
if c.PackageName == "" {
return nil, errors.New("missing required package name")
}
if len(c.ChannelData) == 0 {
return nil, errors.New("missing required channel information")
}
if len(c.BundleData) == 0 {
return nil, errors.New("missing required bundle information")
}

return &c, nil
}

// overrideable func for mocking os.ReadFile
var readFile = func(file string) ([]byte, error) {
return os.ReadFile(file)
}
142 changes: 142 additions & 0 deletions test/operator-e2e/create_fbc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package operatore2e

import (
"bytes"
"encoding/json"
"fmt"
"os"

"github.com/operator-framework/operator-registry/alpha/declcfg"
"github.com/operator-framework/operator-registry/alpha/property"

"github.com/operator-framework/operator-controller/test/operator-e2e/config"
)

const (
SchemaPackage = "olm.package"
SchemaChannel = "olm.channel"
SchemaBundle = "olm.bundle"
SchemaBundleMediatype = "olm.bundle.mediatype"
BundleMediatype = "plain+v0"
)

func CreateFBC(configFilePath string) (*declcfg.DeclarativeConfig, error) {
config, err := config.ReadFile(configFilePath)
if err != nil {
return nil, err
}

dPackage := formPackage(*config)
dChannel := formChannel(*config)
dBundle := formBundle(*config)

fbc := declcfg.DeclarativeConfig{
Packages: []declcfg.Package{dPackage},
Channels: dChannel,
Bundles: dBundle,
}
return &fbc, nil
}

func formPackage(config config.Config) declcfg.Package {
packageFormed := declcfg.Package{
Schema: SchemaPackage,
Name: config.PackageName,
DefaultChannel: config.ChannelData[0].ChannelName,
}
return packageFormed
}

func formChannel(config config.Config) []declcfg.Channel {
channelFormed := make([]declcfg.Channel, 0, len(config.ChannelData))
for _, channel := range config.ChannelData {
channelEntries := formChannelEntries(config.PackageName, channel)
channelFormed = append(channelFormed, declcfg.Channel{
Schema: SchemaChannel,
Name: channel.ChannelName,
Package: config.PackageName,
Entries: channelEntries,
})
}
return channelFormed
}

func formChannelEntries(pkgName string, channel config.ChannelData) []declcfg.ChannelEntry {
channelEntries := make([]declcfg.ChannelEntry, 0, len(channel.ChannelEntries))
for _, channelEntry := range channel.ChannelEntries {
replace := ""
if channelEntry.Replaces != "" {
replace = pkgName + "." + channelEntry.Replaces
}

skip := []string{}
if len(channelEntry.Skips) != 0 {
for _, s := range channelEntry.Skips {
if s != "" {
skip = append(skip, s)
}
}
}
channelEntries = append(channelEntries, declcfg.ChannelEntry{
Name: pkgName + "." + channelEntry.EntryVersion,
Replaces: replace,
Skips: skip,
SkipRange: channelEntry.SkipRange,
})
}
return channelEntries
}

func formBundle(config config.Config) []declcfg.Bundle {
bundleFormed := make([]declcfg.Bundle, 0, len(config.BundleData))
for _, bundle := range config.BundleData {
var properties []property.Property
properties = append(properties, property.Property{
Type: SchemaPackage,
Value: json.RawMessage(fmt.Sprintf(`{"packageName": "%s", "version": "%s"}`, config.PackageName, bundle.BundleVersion)),
})
properties = append(properties, property.Property{
Type: SchemaBundleMediatype,
Value: json.RawMessage(fmt.Sprintf(`"%s"`, BundleMediatype)),
})

bundleFormed = append(bundleFormed, declcfg.Bundle{
Schema: SchemaBundle,
Name: config.PackageName + "." + bundle.BundleVersion,
Package: config.PackageName,
Image: bundle.BundleImage,
Properties: properties,
})
}
return bundleFormed
}

func WriteFBC(fbc declcfg.DeclarativeConfig, fbcFilePath string, fbcFileName string) error {
var buf bytes.Buffer
err := declcfg.WriteYAML(fbc, &buf)
if err != nil {
return err
}

_, err = os.Stat(fbcFilePath)
if os.IsNotExist(err) {
err := os.MkdirAll(fbcFilePath, 0755)
if err != nil {
fmt.Printf("Failed to create directory: %v\n", err)
return err
}
}
file, err := os.Create(fbcFilePath + "/" + fbcFileName)
if err != nil {
fmt.Printf("Failed to create file: %v\n", err)
return err
}
defer file.Close()

err = os.WriteFile(fbcFilePath+"/"+fbcFileName, buf.Bytes(), 0600)
if err != nil {
return err
}

return nil
}
35 changes: 35 additions & 0 deletions test/operator-e2e/generate_dockerfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package operatore2e

import (
"os"
"path/filepath"
"text/template"
)

func generateDockerFile(dockerFilePath string, yamlFolderName string, dockerFileName string) error {
t, err := template.New("dockerfile").Parse(dockerfileTmpl)
if err != nil {
panic(err)
}

dockerFilePath = filepath.Join(dockerFilePath, dockerFileName)
file, err := os.Create(dockerFilePath)
if err != nil {
return err
}
defer file.Close()

_, err = file.WriteString("FROM scratch\n")
if err != nil {
return err
}
err = t.Execute(file, struct{ YamlDir string }{yamlFolderName})
if err != nil {
return err
}

return nil
}

const dockerfileTmpl = `ADD {{.YamlDir}} /configs/{{.YamlDir}}
`
Loading

0 comments on commit cab885b

Please sign in to comment.