mirror of https://github.com/helm/helm
Signed-off-by: Julien Breux <julienbreux@google.com>pull/10922/head
parent
49819b4ef7
commit
5900066f7b
@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/iterator"
|
||||
rspb "helm.sh/helm/v3/pkg/release"
|
||||
)
|
||||
|
||||
const (
|
||||
// GCSDriverName is the string name of this driver.
|
||||
GCSDriverName = "GCS"
|
||||
|
||||
gcsReleaseNameMetadata = "name"
|
||||
gcsReleaseNamespaceMetadata = "namespace"
|
||||
gcsReleaseVersionMetadata = "version"
|
||||
gcsReleaseStatusMetadata = "status"
|
||||
gcsReleaseOwnerColumn = "owner"
|
||||
gcsReleaseCreatedAtMetadata = "createdAt"
|
||||
gcsReleaseModifiedAtMetadata = "modifiedAt"
|
||||
)
|
||||
|
||||
// GCS is the GCS storage driver implementation.
|
||||
type GCS struct {
|
||||
client *storage.Client
|
||||
|
||||
bucket string
|
||||
pathPrefix string
|
||||
|
||||
namespace string
|
||||
|
||||
Log func(string, ...interface{})
|
||||
}
|
||||
|
||||
// NewGCS initializes a new GCS driver.
|
||||
func NewGCS(bucket, pathPrefix, namespace string, logger func(string, ...interface{})) (*GCS, error) {
|
||||
ctx := context.Background()
|
||||
client, err := storage.NewClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
driver := &GCS{
|
||||
client: client,
|
||||
|
||||
bucket: bucket,
|
||||
pathPrefix: pathPrefix,
|
||||
namespace: namespace,
|
||||
|
||||
Log: logger,
|
||||
}
|
||||
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
// Name returns the name of the driver.
|
||||
func (s *GCS) Name() string {
|
||||
return GCSDriverName
|
||||
}
|
||||
|
||||
// Get returns the release named by key or returns ErrReleaseNotFound.
|
||||
func (s *GCS) Get(key string) (*rspb.Release, error) {
|
||||
rel, _, err := s.readRelease(s.fullPathName(key, s.namespace), false)
|
||||
return rel, err
|
||||
}
|
||||
|
||||
// List returns the list of all releases such that filter(release) == true
|
||||
func (s *GCS) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
|
||||
namespaces, err := s.listNamespaces()
|
||||
if err != nil {
|
||||
s.Log("list: failed to list: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var list []*rspb.Release
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
releases, err := s.listReleases(namespace)
|
||||
if err != nil {
|
||||
s.Log("list: failed to list releases in namespace: %v", namespace, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, key := range releases {
|
||||
release, _, err := s.readRelease(key, false)
|
||||
if err != nil {
|
||||
s.Log("list: failed to read release: %v: %v", release, err)
|
||||
continue
|
||||
}
|
||||
if filter(release) {
|
||||
list = append(list, release)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// Query returns the set of releases that match the provided set of labels
|
||||
func (s *GCS) Query(labels map[string]string) ([]*rspb.Release, error) {
|
||||
// List namespaces
|
||||
namespaces, err := s.listNamespaces()
|
||||
if err != nil {
|
||||
s.Log("list: failed to list: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create filter to compare labels and metadata
|
||||
filter := func(metadata map[string]string) bool {
|
||||
for key, val := range labels {
|
||||
if metadataVal, ok := metadata[key]; !ok || metadataVal != val {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// List the releases
|
||||
var list []*rspb.Release
|
||||
for _, namespace := range namespaces {
|
||||
releases, err := s.listReleases(namespace)
|
||||
if err != nil {
|
||||
s.Log("list: failed to list releases in namespace: %v", namespace, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, key := range releases {
|
||||
release, metadata, err := s.readRelease(key, true)
|
||||
if err != nil {
|
||||
s.Log("list: failed to read release: %v: %v", release, err)
|
||||
continue
|
||||
}
|
||||
if filter(metadata) {
|
||||
list = append(list, release)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(list) == 0 {
|
||||
return nil, ErrReleaseNotFound
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// Create creates a new release.
|
||||
func (s *GCS) Create(key string, rls *rspb.Release) error {
|
||||
release, err := encodeRelease(rls)
|
||||
if err != nil {
|
||||
s.Log("failed to encode release: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
obj := s.client.Bucket(s.bucket).
|
||||
Object(s.fullPathName(key, rls.Namespace)).
|
||||
If(storage.Conditions{DoesNotExist: true}).
|
||||
NewWriter(ctx)
|
||||
obj.Metadata = s.metadata(rls, true)
|
||||
|
||||
if _, err := obj.Write([]byte(release)); err != nil {
|
||||
s.Log("failed to write object: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := obj.Close(); err != nil {
|
||||
switch e := err.(type) {
|
||||
case *googleapi.Error:
|
||||
if e.Code == http.StatusPreconditionFailed {
|
||||
s.Log("release %s already exists", key)
|
||||
return ErrReleaseExists
|
||||
}
|
||||
default:
|
||||
s.Log("failed to close bucket: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates a release.
|
||||
func (s *GCS) Update(key string, rls *rspb.Release) error {
|
||||
release, err := encodeRelease(rls)
|
||||
if err != nil {
|
||||
s.Log("failed to encode release: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
obj := s.client.Bucket(s.bucket).Object(s.fullPathName(key, rls.Namespace)).NewWriter(ctx)
|
||||
obj.Metadata = s.metadata(rls, false)
|
||||
if _, err := obj.Write([]byte(release)); err != nil {
|
||||
s.Log("failed to write object: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := obj.Close(); err != nil {
|
||||
s.Log("failed to close object: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes a release or returns ErrReleaseNotFound.
|
||||
func (s *GCS) Delete(key string) (*rspb.Release, error) {
|
||||
ctx := context.Background()
|
||||
obj := s.client.Bucket(s.bucket).Object(s.fullPathName(key, s.namespace))
|
||||
objRdr, err := obj.NewReader(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, storage.ErrObjectNotExist) {
|
||||
err = ErrReleaseNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
record, err := ioutil.ReadAll(objRdr)
|
||||
objRdr.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
release, err := decodeRelease(string(record))
|
||||
if err != nil {
|
||||
s.Log("get: failed to decode data %q: %v", key, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if obj.Delete(ctx); err != nil {
|
||||
s.Log("failed to delete object: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return release, nil
|
||||
}
|
||||
|
||||
// DeletePrefixedReleases deletes all prefixed releases
|
||||
func (s *GCS) DeletePrefixedReleases() error {
|
||||
query := storage.Query{
|
||||
Prefix: fmt.Sprintf("%s/", s.pathPrefix),
|
||||
}
|
||||
ctx := context.Background()
|
||||
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
|
||||
for {
|
||||
objAttrs, err := objs.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
s.Log("unable to delete objects", err)
|
||||
return err
|
||||
}
|
||||
obj := s.client.Bucket(s.bucket).Object(objAttrs.Name)
|
||||
if obj.Delete(ctx); err != nil {
|
||||
s.Log("failed to delete object: (%s) %v", objAttrs.Name, err)
|
||||
}
|
||||
s.Log("object deleted successfully: (%s)", objAttrs.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *GCS) fullPathName(name, namespace string) string {
|
||||
if namespace == "" {
|
||||
namespace = defaultNamespace
|
||||
}
|
||||
return strings.TrimLeft(
|
||||
fmt.Sprintf("%s/%s/%s", s.pathPrefix, namespace, name),
|
||||
"/",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *GCS) metadata(rls *rspb.Release, isCreation bool) map[string]string {
|
||||
ts := strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
|
||||
md := map[string]string{
|
||||
gcsReleaseNameMetadata: rls.Name,
|
||||
gcsReleaseNamespaceMetadata: rls.Namespace,
|
||||
gcsReleaseStatusMetadata: rls.Info.Status.String(),
|
||||
gcsReleaseVersionMetadata: strconv.Itoa(rls.Version),
|
||||
gcsReleaseOwnerColumn: "helm",
|
||||
gcsReleaseModifiedAtMetadata: ts,
|
||||
}
|
||||
if isCreation {
|
||||
md[gcsReleaseCreatedAtMetadata] = ts
|
||||
}
|
||||
return md
|
||||
}
|
||||
|
||||
func (s *GCS) readRelease(key string, withMetadata bool) (*rspb.Release, map[string]string, error) {
|
||||
metadata := make(map[string]string)
|
||||
ctx := context.Background()
|
||||
objHandle := s.client.Bucket(s.bucket).Object(key)
|
||||
obj, err := objHandle.NewReader(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, storage.ErrObjectNotExist) {
|
||||
err = ErrReleaseNotFound
|
||||
}
|
||||
return nil, metadata, err
|
||||
}
|
||||
|
||||
record, err := ioutil.ReadAll(obj)
|
||||
obj.Close()
|
||||
if err != nil {
|
||||
return nil, metadata, err
|
||||
}
|
||||
|
||||
release, err := decodeRelease(string(record))
|
||||
if err != nil {
|
||||
s.Log("read release: failed to decode data %q: %v", key, err)
|
||||
return nil, metadata, err
|
||||
}
|
||||
|
||||
if withMetadata {
|
||||
objAttrs, err := objHandle.Attrs(ctx)
|
||||
if err != nil {
|
||||
s.Log("read release: failed to read metadata %q: %v", key, err)
|
||||
return nil, metadata, err
|
||||
}
|
||||
metadata = objAttrs.Metadata
|
||||
}
|
||||
|
||||
return release, metadata, nil
|
||||
}
|
||||
|
||||
func (s *GCS) listNamespaces() ([]string, error) {
|
||||
if s.namespace != "" {
|
||||
return []string{s.namespace}, nil
|
||||
}
|
||||
|
||||
objectsName := make(map[string]string)
|
||||
|
||||
prefix := fmt.Sprintf("%s/", strings.TrimRight(s.pathPrefix, "/"))
|
||||
query := storage.Query{
|
||||
StartOffset: prefix,
|
||||
Prefix: prefix,
|
||||
}
|
||||
ctx := context.Background()
|
||||
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
|
||||
for {
|
||||
objAttrs, err := objs.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
s.Log("unable to list objects", err)
|
||||
return []string{}, err
|
||||
}
|
||||
objectName, _, _ := strings.Cut(strings.TrimPrefix(objAttrs.Name, prefix), "/")
|
||||
objectsName[objectName] = objectName
|
||||
}
|
||||
|
||||
namespaces := []string{}
|
||||
for objectName := range objectsName {
|
||||
namespaces = append(namespaces, objectName)
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
func (s *GCS) listReleases(namespace string) ([]string, error) {
|
||||
releases := []string{}
|
||||
|
||||
query := storage.Query{
|
||||
Prefix: strings.TrimRight(fmt.Sprintf("%s/%s", s.pathPrefix, namespace), "/"),
|
||||
}
|
||||
ctx := context.Background()
|
||||
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
|
||||
for {
|
||||
objAttrs, err := objs.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
s.Log("unable to list objects", err)
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
releases = append(releases, objAttrs.Name)
|
||||
}
|
||||
|
||||
return releases, nil
|
||||
}
|
@ -0,0 +1,262 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
rspb "helm.sh/helm/v3/pkg/release"
|
||||
)
|
||||
|
||||
var prefixes = []string{"helm-releases", "helm-releases-list"}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
removeReleases()
|
||||
|
||||
retCode := m.Run()
|
||||
|
||||
// removeReleases()
|
||||
|
||||
os.Exit(retCode)
|
||||
}
|
||||
|
||||
func removeReleases() {
|
||||
for _, prefix := range prefixes {
|
||||
gcsDriver := newTestFixtureGCS(prefix, "default")
|
||||
if err := gcsDriver.DeletePrefixedReleases(); err != nil {
|
||||
fmt.Printf("Expected error on setup tests: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSName(t *testing.T) {
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
if gcsDriver.Name() != GCSDriverName {
|
||||
t.Errorf("Expected name to be %s, got %s", GCSDriverName, gcsDriver.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSGet(t *testing.T) {
|
||||
vers := int(1)
|
||||
name := "gcs-test-get"
|
||||
key := testKey(name, vers)
|
||||
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
// create stub
|
||||
if err := gcsDriver.Create(key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", key, err)
|
||||
}
|
||||
|
||||
// test get release
|
||||
got, err := gcsDriver.Get(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get release: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(rel, got) {
|
||||
t.Errorf("Expected release {%v}, got {%v}", rel, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSGetNotExist(t *testing.T) {
|
||||
vers := int(1)
|
||||
name := "gcs-test-get-not-exists"
|
||||
key := testKey(name, vers)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
got, err := gcsDriver.Get(key)
|
||||
if err == nil || got != nil {
|
||||
t.Fatal("Release must be not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSCreate(t *testing.T) {
|
||||
vers := 1
|
||||
name := "gcs-test"
|
||||
key := testKey(name, vers)
|
||||
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
if err := gcsDriver.Create(key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSUpdate(t *testing.T) {
|
||||
vers := 1
|
||||
name := "gcs-test-update"
|
||||
key := testKey(name, vers)
|
||||
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
// create stub
|
||||
if err := gcsDriver.Create(key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", key, err)
|
||||
}
|
||||
|
||||
// test update release
|
||||
if err := gcsDriver.Update(key, rel); err != nil {
|
||||
t.Fatalf("failed to update release with key %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSDelete(t *testing.T) {
|
||||
vers := 1
|
||||
name := "gcs-test-delete"
|
||||
key := testKey(name, vers)
|
||||
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
// create stub
|
||||
if err := gcsDriver.Create(key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", key, err)
|
||||
}
|
||||
|
||||
// test delete release
|
||||
deletedRelease, err := gcsDriver.Delete(key)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to delete release with key %s: %v", key, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(rel, deletedRelease) {
|
||||
t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSDeleteNotFound(t *testing.T) {
|
||||
vers := 1
|
||||
name := "gcs-test-delete-not-found"
|
||||
key := testKey(name, vers)
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases", "default")
|
||||
|
||||
if _, err := gcsDriver.Delete(key); err == nil {
|
||||
t.Fatalf("release found with key %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSList(t *testing.T) {
|
||||
namespaceA := "list-a"
|
||||
namespaceB := "list-b"
|
||||
|
||||
tests := []struct {
|
||||
key string
|
||||
namespace string
|
||||
status rspb.Status
|
||||
}{
|
||||
{"gcs-test-list-key-1", namespaceA, rspb.StatusUninstalled},
|
||||
{"gcs-test-list-key-2", namespaceA, rspb.StatusUninstalled},
|
||||
{"gcs-test-list-key-3", namespaceA, rspb.StatusDeployed},
|
||||
{"gcs-test-list-key-4", namespaceB, rspb.StatusDeployed},
|
||||
{"gcs-test-list-key-5", namespaceB, rspb.StatusSuperseded},
|
||||
{"gcs-test-list-key-6", namespaceB, rspb.StatusSuperseded},
|
||||
}
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases-list", "")
|
||||
|
||||
// create stubs
|
||||
for _, tt := range tests {
|
||||
rel := releaseStub(tt.key, 1, tt.namespace, tt.status)
|
||||
if err := gcsDriver.Create(tt.key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", tt.key, err)
|
||||
}
|
||||
}
|
||||
|
||||
// list all deleted releases
|
||||
del, err := gcsDriver.List(func(rel *rspb.Release) bool {
|
||||
return rel.Info.Status == rspb.StatusUninstalled
|
||||
})
|
||||
// check
|
||||
if err != nil {
|
||||
t.Errorf("Failed to list deleted: %v", err)
|
||||
}
|
||||
if len(del) != 2 {
|
||||
t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del)
|
||||
}
|
||||
|
||||
// list all deployed releases
|
||||
dpl, err := gcsDriver.List(func(rel *rspb.Release) bool {
|
||||
return rel.Info.Status == rspb.StatusDeployed
|
||||
})
|
||||
// check
|
||||
if err != nil {
|
||||
t.Errorf("Failed to list deployed: %v", err)
|
||||
}
|
||||
if len(dpl) != 2 {
|
||||
t.Errorf("Expected 2 deployed, got %d:\n%+v\n", len(dpl), dpl)
|
||||
}
|
||||
|
||||
// list all superseded releases
|
||||
ssd, err := gcsDriver.List(func(rel *rspb.Release) bool {
|
||||
return rel.Info.Status == rspb.StatusSuperseded
|
||||
})
|
||||
// check
|
||||
if err != nil {
|
||||
t.Errorf("Failed to list superseded: %v", err)
|
||||
}
|
||||
if len(ssd) != 2 {
|
||||
t.Errorf("Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCSQuery(t *testing.T) {
|
||||
namespace := "default"
|
||||
tests := []struct {
|
||||
key string
|
||||
namespace string
|
||||
status rspb.Status
|
||||
}{
|
||||
{"gcs-test-list-key-1", namespace, rspb.StatusUninstalled},
|
||||
{"gcs-test-list-key-2", namespace, rspb.StatusUninstalled},
|
||||
{"gcs-test-list-key-3", namespace, rspb.StatusDeployed},
|
||||
{"gcs-test-list-key-4", namespace, rspb.StatusDeployed},
|
||||
{"gcs-test-list-key-5", namespace, rspb.StatusSuperseded},
|
||||
{"gcs-test-list-key-6", namespace, rspb.StatusSuperseded},
|
||||
}
|
||||
|
||||
gcsDriver := newTestFixtureGCS("helm-releases-query", "")
|
||||
|
||||
// create stubs
|
||||
for _, tt := range tests {
|
||||
rel := releaseStub(tt.key, 1, tt.namespace, tt.status)
|
||||
if err := gcsDriver.Create(tt.key, rel); err != nil {
|
||||
t.Fatalf("failed to create release with key %s: %v", tt.key, err)
|
||||
}
|
||||
}
|
||||
|
||||
rls, err := gcsDriver.Query(map[string]string{"status": "deployed"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to query: %s", err)
|
||||
}
|
||||
if len(rls) != 2 {
|
||||
t.Fatalf("Expected 2 results, actual %d", len(rls))
|
||||
}
|
||||
|
||||
_, err = gcsDriver.Query(map[string]string{"name": "notExist"})
|
||||
if err != ErrReleaseNotFound {
|
||||
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
|
||||
}
|
||||
}
|
Loading…
Reference in new issue