Skip to content

Commit eacb9a4

Browse files
Merge pull request #685 from zcahana/bundle_gzip
Add an option to store Gzip-encoded bundle data in ConfigMaps
2 parents 9114e6a + 8720e3d commit eacb9a4

File tree

236 files changed

+23053
-697
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+23053
-697
lines changed

cmd/opm/alpha/bundle/extract.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func init() {
3131
extractCmd.Flags().StringP("configmapname", "c", "", "name of configmap to write bundle data")
3232
extractCmd.Flags().StringP("namespace", "n", "openshift-operator-lifecycle-manager", "namespace to write configmap data")
3333
extractCmd.Flags().Uint64P("datalimit", "l", 1<<20, "maximum limit in bytes for total bundle data")
34+
extractCmd.Flags().BoolP("gzip", "z", false, "enable gzip compression of configmap data")
3435
extractCmd.MarkPersistentFlagRequired("configmapname")
3536
}
3637

@@ -55,8 +56,12 @@ func runExtractCmd(cmd *cobra.Command, args []string) error {
5556
if err != nil {
5657
return err
5758
}
59+
gzip, err := cmd.Flags().GetBool("gzip")
60+
if err != nil {
61+
return err
62+
}
5863

59-
loader := configmap.NewConfigMapLoaderForDirectory(configmapName, namespace, manifestsDir, kubeconfig)
64+
loader := configmap.NewConfigMapLoader(configmapName, namespace, manifestsDir, gzip, kubeconfig)
6065
if err := loader.Populate(datalimit); err != nil {
6166
return fmt.Errorf("error loading manifests from directory: %s", err)
6267
}

pkg/configmap/configmap.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
corev1 "k8s.io/api/core/v1"
1010

1111
"github.com/operator-framework/operator-registry/pkg/api"
12+
"github.com/operator-framework/operator-registry/pkg/lib/encoding"
1213
"github.com/operator-framework/operator-registry/pkg/registry"
1314
)
1415

@@ -41,7 +42,7 @@ func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error
4142
"configmap": fmt.Sprintf("%s/%s", cm.GetNamespace(), cm.GetName()),
4243
})
4344

44-
bundle, skipped, bundleErr := loadBundle(logger, cm.Data)
45+
bundle, skipped, bundleErr := loadBundle(logger, cm)
4546
if bundleErr != nil {
4647
err = fmt.Errorf("failed to extract bundle from configmap - %v", bundleErr)
4748
return
@@ -50,10 +51,21 @@ func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error
5051
return
5152
}
5253

53-
func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *api.Bundle, skipped map[string]string, err error) {
54+
func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (bundle *api.Bundle, skipped map[string]string, err error) {
5455
bundle = &api.Bundle{Object: []string{}}
5556
skipped = map[string]string{}
5657

58+
data := cm.Data
59+
if hasGzipEncodingAnnotation(cm) {
60+
entry.Debug("Decoding gzip-encoded bundle data")
61+
62+
var err error
63+
data, err = decodeGzipBinaryData(cm)
64+
if err != nil {
65+
return nil, nil, err
66+
}
67+
}
68+
5769
// Add kube resources to the bundle.
5870
for name, content := range data {
5971
reader := strings.NewReader(content)
@@ -85,3 +97,18 @@ func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *api.Bundle
8597

8698
return
8799
}
100+
101+
func decodeGzipBinaryData(cm *corev1.ConfigMap) (map[string]string, error) {
102+
data := map[string]string{}
103+
104+
for name, content := range cm.BinaryData {
105+
decoded, err := encoding.GzipBase64Decode(content)
106+
if err != nil {
107+
return nil, fmt.Errorf("error decoding gzip-encoded bundle data: %v", err)
108+
}
109+
110+
data[name] = string(decoded)
111+
}
112+
113+
return data, nil
114+
}

pkg/configmap/configmap_test.go

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package configmap
22

33
import (
4+
"context"
45
"os"
5-
"strings"
66
"testing"
77

88
"github.com/operator-framework/operator-registry/pkg/api"
9+
unstructuredlib "github.com/operator-framework/operator-registry/pkg/lib/unstructured"
910
"github.com/stretchr/testify/assert"
1011
"github.com/stretchr/testify/require"
1112
corev1 "k8s.io/api/core/v1"
12-
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
"k8s.io/apimachinery/pkg/util/yaml"
15+
"k8s.io/client-go/kubernetes/fake"
16+
)
17+
18+
const (
19+
configMapName = "test-configmap"
20+
configMapNamespace = "test-namespace"
1421
)
1522

1623
func TestLoad(t *testing.T) {
@@ -40,7 +47,8 @@ func TestLoad(t *testing.T) {
4047
assert.NotNil(t, objects)
4148
assert.Equal(t, 1, len(objects))
4249

43-
unst := getUnstructured(t, objects[0])
50+
unst, err := unstructuredlib.FromString(objects[0])
51+
assert.NoError(t, err)
4452
assert.True(t, unst.GetKind() == "Foo")
4553
},
4654
},
@@ -51,7 +59,8 @@ func TestLoad(t *testing.T) {
5159
csvGot := bundleGot.GetCsvJson()
5260
assert.NotNil(t, csvGot)
5361

54-
unst := getUnstructured(t, csvGot)
62+
unst, err := unstructuredlib.FromString(csvGot)
63+
assert.NoError(t, err)
5564
assert.True(t, unst.GetName() == "first" || unst.GetName() == "second")
5665
},
5766
},
@@ -69,7 +78,8 @@ func TestLoad(t *testing.T) {
6978
assertFunc: func(t *testing.T, bundleGot *api.Bundle) {
7079
csvGot := bundleGot.GetCsvJson()
7180
assert.NotNil(t, csvGot)
72-
unst := getUnstructured(t, csvGot)
81+
unst, err := unstructuredlib.FromString(csvGot)
82+
assert.NoError(t, err)
7383
assert.True(t, unst.GetName() == "kiali-operator.v1.4.2")
7484

7585
objects := bundleGot.GetObject()
@@ -83,7 +93,8 @@ func TestLoad(t *testing.T) {
8393
assertFunc: func(t *testing.T, bundleGot *api.Bundle) {
8494
csvGot := bundleGot.GetCsvJson()
8595
assert.NotNil(t, csvGot)
86-
unst := getUnstructured(t, csvGot)
96+
unst, err := unstructuredlib.FromString(csvGot)
97+
assert.NoError(t, err)
8798
assert.True(t, unst.GetName() == "kiali-operator.v1.4.2")
8899

89100
objects := bundleGot.GetObject()
@@ -109,6 +120,56 @@ func TestLoad(t *testing.T) {
109120
}
110121
}
111122

123+
func TestLoadWriteRead(t *testing.T) {
124+
tests := []struct {
125+
name string
126+
source string
127+
gzip bool
128+
}{
129+
{
130+
name: "BundleUncompressed",
131+
source: "testdata/bundles/etcd.0.9.2/",
132+
gzip: false,
133+
},
134+
{
135+
name: "BundleCompressed",
136+
source: "testdata/bundles/etcd.0.9.2/",
137+
gzip: true,
138+
},
139+
}
140+
141+
for _, tt := range tests {
142+
t.Run(tt.name, func(t *testing.T) {
143+
cm := &corev1.ConfigMap{
144+
ObjectMeta: metav1.ObjectMeta{
145+
Name: configMapName,
146+
Namespace: configMapNamespace,
147+
},
148+
}
149+
clientset := fake.NewSimpleClientset()
150+
clientset.CoreV1().ConfigMaps(configMapNamespace).Create(context.TODO(), cm, metav1.CreateOptions{})
151+
152+
cmLoader := NewConfigMapLoaderWithClient(configMapName, configMapNamespace, tt.source, tt.gzip, clientset)
153+
err := cmLoader.Populate(1 << 20)
154+
assert.NoError(t, err)
155+
156+
cm, err = clientset.CoreV1().ConfigMaps(configMapNamespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
157+
assert.NoError(t, err)
158+
159+
bundleLoader := NewBundleLoader()
160+
bundle, err := bundleLoader.Load(cm)
161+
162+
expectedObjects, err := unstructuredlib.FromDir(tt.source + "manifests/")
163+
assert.NoError(t, err)
164+
165+
bundleObjects, err := unstructuredlib.FromBundle(bundle)
166+
assert.NoError(t, err)
167+
168+
assert.ElementsMatch(t, expectedObjects, bundleObjects)
169+
})
170+
}
171+
}
172+
112173
func loadfromFile(t *testing.T, path string) *corev1.ConfigMap {
113174
reader, err := os.Open(path)
114175
require.NoError(t, err, "unable to load from file %s", path)
@@ -120,11 +181,3 @@ func loadfromFile(t *testing.T, path string) *corev1.ConfigMap {
120181

121182
return bundle
122183
}
123-
124-
func getUnstructured(t *testing.T, str string) *unstructured.Unstructured {
125-
dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(str), 1)
126-
unst := &unstructured.Unstructured{}
127-
err := dec.Decode(unst)
128-
assert.NoError(t, err)
129-
return unst
130-
}

0 commit comments

Comments
 (0)