Commit 2eed3f04 authored by Matt Butcher's avatar Matt Butcher Committed by GitHub

Merge pull request #1420 from databus23/compression

Add compression to configmap storage driver
parents b0c113df eb4b78bb
...@@ -17,8 +17,11 @@ limitations under the License. ...@@ -17,8 +17,11 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver" package driver // import "k8s.io/helm/pkg/storage/driver"
import ( import (
"bytes"
"compress/gzip"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"strconv" "strconv"
"time" "time"
...@@ -40,6 +43,8 @@ const ConfigMapsDriverName = "ConfigMap" ...@@ -40,6 +43,8 @@ const ConfigMapsDriverName = "ConfigMap"
var b64 = base64.StdEncoding var b64 = base64.StdEncoding
var magicGzip = []byte{0x1f, 0x8b, 0x08}
// ConfigMaps is a wrapper around an implementation of a kubernetes // ConfigMaps is a wrapper around an implementation of a kubernetes
// ConfigMapsInterface. // ConfigMapsInterface.
type ConfigMaps struct { type ConfigMaps struct {
...@@ -254,13 +259,23 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*api.Config ...@@ -254,13 +259,23 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*api.Config
} }
// encodeRelease encodes a release returning a base64 encoded // encodeRelease encodes a release returning a base64 encoded
// binary protobuf encoding representation, or error. // gzipped binary protobuf encoding representation, or error.
func encodeRelease(rls *rspb.Release) (string, error) { func encodeRelease(rls *rspb.Release) (string, error) {
b, err := proto.Marshal(rls) b, err := proto.Marshal(rls)
if err != nil { if err != nil {
return "", err return "", err
} }
return b64.EncodeToString(b), nil var buf bytes.Buffer
w, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
if err != nil {
return "", err
}
if _, err = w.Write(b); err != nil {
return "", err
}
w.Close()
return b64.EncodeToString(buf.Bytes()), nil
} }
// decodeRelease decodes the bytes in data into a release // decodeRelease decodes the bytes in data into a release
...@@ -274,6 +289,21 @@ func decodeRelease(data string) (*rspb.Release, error) { ...@@ -274,6 +289,21 @@ func decodeRelease(data string) (*rspb.Release, error) {
return nil, err return nil, err
} }
// For backwards compatibility with releases that were stored before
// compression was introduced we skip decompression if the
// gzip magic header is not found
if bytes.Equal(b[0:3], magicGzip) {
r, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
return nil, err
}
b2, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
b = b2
}
var rls rspb.Release var rls rspb.Release
// unmarshal protobuf bytes // unmarshal protobuf bytes
if err := proto.Unmarshal(b, &rls); err != nil { if err := proto.Unmarshal(b, &rls); err != nil {
......
...@@ -14,10 +14,14 @@ limitations under the License. ...@@ -14,10 +14,14 @@ limitations under the License.
package driver package driver
import ( import (
"encoding/base64"
"reflect" "reflect"
"testing" "testing"
"github.com/gogo/protobuf/proto"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/kubernetes/pkg/api"
) )
func TestConfigMapName(t *testing.T) { func TestConfigMapName(t *testing.T) {
...@@ -46,6 +50,37 @@ func TestConfigMapGet(t *testing.T) { ...@@ -46,6 +50,37 @@ func TestConfigMapGet(t *testing.T) {
} }
} }
func TestUNcompressedConfigMapGet(t *testing.T) {
vers := int32(1)
name := "smug-pigeon"
key := testKey(name, vers)
rel := releaseStub(name, vers, rspb.Status_DEPLOYED)
// Create a test fixture which contains an uncompressed release
cfgmap, err := newConfigMapsObject(key, rel, nil)
if err != nil {
t.Fatalf("Failed to create configmap: %s", err)
}
b, err := proto.Marshal(rel)
if err != nil {
t.Fatalf("Failed to marshal release: %s", err)
}
cfgmap.Data["release"] = base64.StdEncoding.EncodeToString(b)
var mock MockConfigMapsInterface
mock.objects = map[string]*api.ConfigMap{key: cfgmap}
cfgmaps := NewConfigMaps(&mock)
// get release with key
got, err := cfgmaps.Get(key)
if err != nil {
t.Fatalf("Failed to get release: %s", err)
}
// compare fetched release with original
if !reflect.DeepEqual(rel, got) {
t.Errorf("Expected {%q}, got {%q}", rel, got)
}
}
func TestConfigMapList(t *testing.T) { func TestConfigMapList(t *testing.T) {
cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{ cfgmaps := newTestFixtureCfgMaps(t, []*rspb.Release{
releaseStub("key-1", 1, rspb.Status_DELETED), releaseStub("key-1", 1, rspb.Status_DELETED),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment