Skip to content

Commit 57d8364

Browse files
committedOct 18, 2018
feat(configmap): add configmap loader
This is to support the older catalog format, which stores data in a configmap
1 parent 06f1c06 commit 57d8364

13 files changed

+7642
-76
lines changed
 

‎.dockerignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin
2+
*.db

‎.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@
1010

1111
# Output of the go coverage tool, specifically when used with LiteIDE
1212
*.out
13+
14+
# Ignore binaries
15+
bin
16+
17+
# Ignore sqlite
18+
*.db

‎Dockerfile

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
FROM golang:1.10-alpine
1+
FROM golang:1.10-alpine as builder
22

33
RUN apk update && apk add sqlite build-base
44
WORKDIR /go/src/github.com/operator-framework/operator-registry
55

66
COPY vendor vendor
77
COPY cmd cmd
88
COPY pkg pkg
9-
RUN go build --tags json1 -o ./initializer ./cmd/init/...
9+
COPY Makefile Makefile
10+
RUN make build
1011

1112
COPY manifests manifests
12-
RUN ./initializer
13+
RUN ./bin/initializer -o ./bundles.db
1314

15+
FROM scratch
16+
COPY --from=builder /go/src/github.com/operator-framework/operator-registry/bundles.db /bundles.db
1417

‎Gopkg.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.PHONY: build test vendor
2+
3+
all: test build
4+
5+
test:
6+
go test --tags json1 -v -race ./pkg/...
7+
8+
build:
9+
go build --tags json1 -o ./bin/initializer ./cmd/init/...
10+
11+
image:
12+
docker build .
13+
14+
vendor:
15+
dep ensure -v

‎configmap.example.yaml

+7,251
Large diffs are not rendered by default.

‎initializer

-35.6 MB
Binary file not shown.

‎pkg/registry/bundle.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package registry
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
8+
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
9+
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
"k8s.io/apimachinery/pkg/runtime/serializer"
13+
)
14+
15+
// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered.
16+
var Scheme = runtime.NewScheme()
17+
18+
// Codecs provides access to encoding and decoding for the scheme
19+
var Codecs = serializer.NewCodecFactory(Scheme)
20+
21+
func DefaultYAMLDecoder() runtime.Decoder {
22+
return Codecs.UniversalDeserializer()
23+
}
24+
25+
func init() {
26+
if err := v1alpha1.AddToScheme(Scheme); err != nil {
27+
panic(err)
28+
}
29+
30+
if err := v1beta1.AddToScheme(Scheme); err != nil {
31+
panic(err)
32+
}
33+
}
34+
35+
func ProvidedAPIs(objs []*unstructured.Unstructured) (map[APIKey]struct{}, error) {
36+
provided := map[APIKey]struct{}{}
37+
for _, o := range objs {
38+
if o.GetObjectKind().GroupVersionKind().Kind == "CustomResourceDefinition" {
39+
crd := &apiextensions.CustomResourceDefinition{}
40+
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.UnstructuredContent(), crd); err != nil {
41+
return nil, err
42+
}
43+
for _, v := range crd.Spec.Versions {
44+
provided[APIKey{Group: crd.Spec.Group, Version: v.Name, Kind: crd.Spec.Names.Kind}] = struct{}{}
45+
}
46+
if crd.Spec.Version != "" {
47+
provided[APIKey{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.Kind}] = struct{}{}
48+
}
49+
}
50+
51+
//TODO: APIServiceDefinitions
52+
}
53+
return provided, nil
54+
}
55+
56+
func AllProvidedAPIsInBundle(csv *v1alpha1.ClusterServiceVersion, bundleAPIs map[APIKey]struct{}) error {
57+
shouldExist := make(map[APIKey]struct{}, len(csv.Spec.CustomResourceDefinitions.Owned)+len(csv.Spec.APIServiceDefinitions.Owned))
58+
for _, crdDef := range csv.Spec.CustomResourceDefinitions.Owned {
59+
parts := strings.SplitAfterN(crdDef.Name, ".", 2)
60+
shouldExist[APIKey{parts[1], crdDef.Version, crdDef.Kind}] = struct{}{}
61+
}
62+
//TODO: APIServiceDefinitions
63+
for key := range shouldExist {
64+
if _, ok := bundleAPIs[key]; !ok {
65+
return fmt.Errorf("couldn't find %v in bundle", key)
66+
}
67+
}
68+
return nil
69+
}

‎pkg/registry/types.go

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package registry
22

3+
// APIKey stores GroupVersionKind for use as map keys
4+
type APIKey struct {
5+
Group string
6+
Version string
7+
Kind string
8+
}
9+
310
// PackageManifest holds information about a package, which is a reference to one (or more)
411
// channels under a single package.
512
type PackageManifest struct {

‎pkg/sqlite/configmap.go

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package sqlite
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/ghodss/yaml"
9+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
10+
"github.com/operator-framework/operator-registry/pkg/registry"
11+
"github.com/sirupsen/logrus"
12+
"k8s.io/api/core/v1"
13+
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
14+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15+
"k8s.io/apimachinery/pkg/runtime"
16+
)
17+
18+
const (
19+
ConfigMapCRDName = "customResourceDefinitions"
20+
ConfigMapCSVName = "clusterServiceVersions"
21+
ConfigMapPackageName = "packages"
22+
)
23+
24+
// ConfigMapLoader loads a configmap of resources into the database
25+
// entries under "customResourceDefinitions" will be parsed as CRDs
26+
// entries under "clusterServiceVersions" will be parsed as CSVs
27+
// entries under "packages" will be parsed as Packages
28+
type ConfigMapLoader struct {
29+
store registry.Load
30+
configMap v1.ConfigMap
31+
crds map[registry.APIKey]*unstructured.Unstructured
32+
}
33+
34+
var _ SQLPopulator = &ConfigMapLoader{}
35+
36+
func NewSQLLoaderForConfigMap(store registry.Load, configMap v1.ConfigMap) *ConfigMapLoader {
37+
return &ConfigMapLoader{
38+
store: store,
39+
configMap: configMap,
40+
crds: map[registry.APIKey]*unstructured.Unstructured{},
41+
}
42+
}
43+
44+
func (c *ConfigMapLoader) Populate() error {
45+
log := logrus.WithFields(logrus.Fields{"configmap": c.configMap.GetName(), "ns": c.configMap.GetNamespace()})
46+
log.Info("loading CRDs")
47+
48+
// first load CRDs into memory; these will be added to the bundle that owns them
49+
crdListYaml, ok := c.configMap.Data[ConfigMapCRDName]
50+
if !ok {
51+
return fmt.Errorf("couldn't find expected key %s in configmap", ConfigMapCRDName)
52+
}
53+
54+
crdListJson, err := yaml.YAMLToJSON([]byte(crdListYaml))
55+
if err != nil {
56+
log.WithError(err).Debug("error loading CRD list")
57+
return err
58+
}
59+
60+
var parsedCRDList []v1beta1.CustomResourceDefinition
61+
if err := json.Unmarshal(crdListJson, &parsedCRDList); err!=nil {
62+
log.WithError(err).Debug("error parsing CRD list")
63+
return err
64+
}
65+
66+
for _, crd := range parsedCRDList {
67+
if crd.Spec.Versions == nil && crd.Spec.Version != "" {
68+
crd.Spec.Versions = []v1beta1.CustomResourceDefinitionVersion{{Name: crd.Spec.Version, Served: true, Storage: true}}
69+
}
70+
for _, version := range crd.Spec.Versions {
71+
gvk := registry.APIKey{crd.Spec.Group, version.Name, crd.Spec.Names.Kind}
72+
log.WithField("gvk", gvk).Debug("loading CRD")
73+
if _, ok := c.crds[gvk]; ok {
74+
log.WithField("gvk", gvk).Debug("crd added twice")
75+
return fmt.Errorf("can't add the same CRD twice in one configmap")
76+
}
77+
crdUnst, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&crd)
78+
if err != nil {
79+
log.WithError(err).Debug("error remarshalling crd")
80+
return err
81+
}
82+
c.crds[gvk] = &unstructured.Unstructured{Object: crdUnst}
83+
}
84+
}
85+
86+
log.Info("loading Bundles")
87+
csvListYaml, ok := c.configMap.Data[ConfigMapCSVName]
88+
if !ok {
89+
return fmt.Errorf("couldn't find expected key %s in configmap", ConfigMapCSVName)
90+
}
91+
csvListJson, err := yaml.YAMLToJSON([]byte(csvListYaml))
92+
if err != nil {
93+
log.WithError(err).Debug("error loading CSV list")
94+
return err
95+
}
96+
97+
var parsedCSVList []v1alpha1.ClusterServiceVersion
98+
err = json.Unmarshal([]byte(csvListJson), &parsedCSVList)
99+
if err != nil {
100+
log.WithError(err).Debug("error parsing CSV list")
101+
return err
102+
}
103+
104+
for _, csv := range parsedCSVList {
105+
log.WithField("csv", csv.Name).Debug("loading CSV")
106+
csvUnst, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&csv)
107+
if err != nil {
108+
log.WithError(err).Debug("error remarshalling csv")
109+
return err
110+
}
111+
112+
bundle := []*unstructured.Unstructured{{Object: csvUnst}}
113+
for _, owned := range csv.Spec.CustomResourceDefinitions.Owned {
114+
split := strings.SplitAfterN(owned.Name, ".", 2)
115+
if len(split) < 2 {
116+
log.WithError(err).Debug("error parsing owned name")
117+
return fmt.Errorf("error parsing owned name")
118+
}
119+
gvk := registry.APIKey{split[1], owned.Version, owned.Kind}
120+
if crdUnst, ok := c.crds[gvk]; !ok {
121+
log.WithField("gvk", gvk).WithError(err).Debug("couldn't find owned CRD in crd list")
122+
} else {
123+
bundle = append(bundle, crdUnst)
124+
}
125+
}
126+
127+
if err := c.store.AddOperatorBundle(bundle); err != nil {
128+
return err
129+
}
130+
}
131+
132+
log.Info("loading Packages")
133+
packageListYaml, ok := c.configMap.Data[ConfigMapPackageName]
134+
if !ok {
135+
return fmt.Errorf("couldn't find expected key %s in configmap", ConfigMapPackageName)
136+
}
137+
138+
packageListJson, err := yaml.YAMLToJSON([]byte(packageListYaml))
139+
if err != nil {
140+
log.WithError(err).Debug("error loading package list")
141+
return err
142+
}
143+
144+
var parsedPackageManifests []registry.PackageManifest
145+
err = json.Unmarshal([]byte(packageListJson), &parsedPackageManifests)
146+
if err != nil {
147+
log.WithError(err).Debug("error parsing package list")
148+
return err
149+
}
150+
for _, packageManifest := range parsedPackageManifests {
151+
log.WithField("package", packageManifest.PackageName).Debug("loading package")
152+
if err := c.store.AddPackageChannels(packageManifest); err != nil {
153+
return err
154+
}
155+
}
156+
157+
log.Info("extracting provided API information")
158+
if err := c.store.AddProvidedApis(); err != nil {
159+
return err
160+
}
161+
return nil
162+
}

‎pkg/sqlite/configmap_test.go

+102
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.