pull/1008/merge
Brian 9 years ago committed by GitHub
commit f32a9431ae

@ -0,0 +1,53 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 "k8s.io/helm/pkg/storage/driver"
import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
type ConfigMaps struct {
*Memory // simple cache
}
func NewConfigMaps() *ConfigMaps {
return &ConfigMaps{Memory: NewMemory()}
}
// Get retrieves the releases named by key from the ConfigMap
func (cfg *ConfigMaps) Get(key string) (*rspb.Release, error) {
return nil, ErrNotImplemented
}
// All returns all releases whose status is not Status_DELETED.
func (cfg *ConfigMaps) All(key string, opts ...interface{}) ([]*rspb.Release, error) {
return nil, ErrNotImplemented
}
// Create creates a new release or error.
func (cfg *ConfigMaps) Create(rls *rspb.Release) error {
return ErrNotImplemented
}
// Update updates a release or error.
func (cfg *ConfigMaps) Update(rls *rspb.Release) error {
return ErrNotImplemented
}
// Delete deletes a release or error.
func (cfg *ConfigMaps) Delete(key string) (*rspb.Release, error) {
return nil, ErrNotImplemented
}

@ -0,0 +1,40 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 "k8s.io/helm/pkg/storage/driver"
import (
"testing"
)
func TestConfigMapsGet(t *testing.T) {
t.Skip("ConfigMapsGet")
}
func TestConfigMapsAll(t *testing.T) {
t.Skip("ConfigMapsAll")
}
func TestConfigMapsCreate(t *testing.T) {
t.Skip("ConfigMapsCreate")
}
func TestConfigMapsUpdate(t *testing.T) {
t.Skip("ConfigMapsUpdate")
}
func TestConfigMapsDelete(t *testing.T) {
t.Skip("ConfigMapsDelete")
}

@ -0,0 +1,53 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 "k8s.io/helm/pkg/storage/driver"
import (
"errors"
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
var (
// ErrReleaseNotFound indicates that a release is not found.
ErrReleaseNotFound = errors.New("release not found")
// Temporary error while WIP.
ErrNotImplemented = errors.New("not implemented")
)
type Creator interface {
Create(*rspb.Release) error
}
type Updator interface {
Update(*rspb.Release) error
}
type Deletor interface {
Delete(string) (*rspb.Release, error)
}
type Queryor interface {
Get(string) (*rspb.Release, error)
All(string, ...interface{}) ([]*rspb.Release, error)
}
type Driver interface {
Creator
Updator
Deletor
Queryor
}

@ -0,0 +1,106 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 "k8s.io/helm/pkg/storage/driver"
import (
"sync"
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
// Memory is an in-memory storage driver implementation.
type Memory struct {
sync.RWMutex
cache map[string]*rspb.Release
}
func NewMemory() *Memory {
return &Memory{cache: map[string]*rspb.Release{}}
}
// Get returns the release named by key.
func (mem *Memory) Get(key string) (*rspb.Release, error) {
defer unlock(mem.rlock())
if rls, ok := mem.cache[key]; ok {
return rls, nil
}
return nil, ErrReleaseNotFound
}
// All returns all releases whose status is not Status_DELETED.
func (mem *Memory) All(key string, opts ...interface{}) ([]*rspb.Release, error) {
defer unlock(mem.rlock())
var releases []*rspb.Release
for _, rls := range mem.cache {
if rls.Info.Status.Code != rspb.Status_DELETED {
releases = append(releases, rls)
}
}
return releases, nil
}
// Create creates a new release or error.
func (mem *Memory) Create(rls *rspb.Release) error {
defer unlock(mem.wlock())
mem.cache[rls.Name] = rls
return nil
}
// Update updates a release or error.
func (mem *Memory) Update(rls *rspb.Release) error {
defer unlock(mem.wlock())
if old, ok := mem.cache[rls.Name]; ok {
// FIXME: when release update is complete, old release should
// be marked as superseded, creating the new release.
_ = old
mem.cache[rls.Name] = rls
return nil
}
return ErrReleaseNotFound
}
// Delete deletes a release or error.
func (mem *Memory) Delete(key string) (*rspb.Release, error) {
defer unlock(mem.wlock())
if old, ok := mem.cache[key]; ok {
old.Info.Status.Code = rspb.Status_DELETED
delete(mem.cache, key)
return old, nil
}
return nil, ErrReleaseNotFound
}
func (mem *Memory) wlock() func() {
mem.Lock()
return func() {
mem.Unlock()
}
}
func (mem *Memory) rlock() func() {
mem.RLock()
return func() {
mem.RUnlock()
}
}
func unlock(fn func()) { fn() }

@ -0,0 +1,97 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 "k8s.io/helm/pkg/storage/driver"
import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
"testing"
)
func TestMemoryGet(t *testing.T) {
key := "test-1"
rls := &rspb.Release{Name: key}
mem := NewMemory()
mem.Create(rls)
res, err := mem.Get(key)
switch {
case err != nil:
t.Errorf("Could not get %s: %s", key, err)
case res.Name != key:
t.Errorf("Expected %s, got %s", key, res.Name)
}
}
func TestMemoryAll(t *testing.T) {
t.Skip("MemoryAll")
}
func TestMemoryCreate(t *testing.T) {
key := "test-1"
rls := &rspb.Release{Name: key}
mem := NewMemory()
err := mem.Create(rls)
switch {
case err != nil:
t.Fatalf("Failed create: %s", err)
case mem.cache[key].Name != key:
t.Errorf("Unexpected release name: %s", mem.cache[key].Name)
}
}
func TestMemoryUpdate(t *testing.T) {
key := "test-1"
rls := &rspb.Release{Name: key}
mem := NewMemory()
if err := mem.Create(rls); err != nil {
t.Fatalf("Failed create: %s", err)
}
if err := mem.Update(rls); err != nil {
t.Fatalf("Failed update: %s", err)
}
if mem.cache[key].Name != key {
t.Errorf("Unexpected release name: %s", mem.cache[key].Name)
}
}
func TestMemoryDelete(t *testing.T) {
key := "test-1"
rls := &rspb.Release{
Name: key,
Info: &rspb.Info{
Status: &rspb.Status{Code: rspb.Status_DEPLOYED},
},
}
mem := NewMemory()
if err := mem.Create(rls); err != nil {
t.Fatalf("Failed create: %s", err)
}
res, err := mem.Delete(key)
switch {
case err != nil:
t.Fatalf("Failed delete: %s", err)
case mem.cache[key] != nil:
t.Errorf("Expected nil, got %s", mem.cache[key])
case res.Info.Status.Code != rspb.Status_DELETED:
t.Errorf("Expected Status_DELETED, got %s", res.Info.Status.Code)
}
}

@ -1,118 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 storage
import (
"errors"
"sync"
"k8s.io/helm/pkg/proto/hapi/release"
)
// Memory is an in-memory ReleaseStorage implementation.
type Memory struct {
sync.RWMutex
releases map[string]*release.Release
}
// NewMemory creates a new in-memory storage.
func NewMemory() *Memory {
return &Memory{
releases: map[string]*release.Release{},
}
}
// ErrNotFound indicates that a release is not found.
var ErrNotFound = errors.New("release not found")
// Read returns the named Release.
//
// If the release is not found, an ErrNotFound error is returned.
func (m *Memory) Read(k string) (*release.Release, error) {
m.RLock()
defer m.RUnlock()
v, ok := m.releases[k]
if !ok {
return v, ErrNotFound
}
return v, nil
}
// Create sets a release.
func (m *Memory) Create(rel *release.Release) error {
m.Lock()
defer m.Unlock()
m.releases[rel.Name] = rel
return nil
}
// Update sets a release.
func (m *Memory) Update(rel *release.Release) error {
m.Lock()
defer m.Unlock()
if _, ok := m.releases[rel.Name]; !ok {
return ErrNotFound
}
// FIXME: When Release is done, we need to do this right by marking the old
// release as superseded, and creating a new release.
m.releases[rel.Name] = rel
return nil
}
// Delete removes a release.
func (m *Memory) Delete(name string) (*release.Release, error) {
m.Lock()
defer m.Unlock()
rel, ok := m.releases[name]
if !ok {
return nil, ErrNotFound
}
delete(m.releases, name)
return rel, nil
}
// List returns all releases whose status is not Status_DELETED.
func (m *Memory) List() ([]*release.Release, error) {
m.RLock()
defer m.RUnlock()
buf := []*release.Release{}
for _, v := range m.releases {
if v.Info.Status.Code != release.Status_DELETED {
buf = append(buf, v)
}
}
return buf, nil
}
// Query searches all releases for matches.
func (m *Memory) Query(labels map[string]string) ([]*release.Release, error) {
m.RLock()
defer m.RUnlock()
return []*release.Release{}, errors.New("not implemented")
}
// History returns the history of this release, in the form of a series of releases.
func (m *Memory) History(name string) ([]*release.Release, error) {
// TODO: This _should_ return all of the releases with the given name, sorted
// by LastDeployed, regardless of status.
r, err := m.Read(name)
if err != nil {
return []*release.Release{}, err
}
return []*release.Release{r}, nil
}

@ -1,130 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 storage
import (
"testing"
"k8s.io/helm/pkg/proto/hapi/release"
)
func TestCreate(t *testing.T) {
k := "test-1"
r := &release.Release{Name: k}
ms := NewMemory()
if err := ms.Create(r); err != nil {
t.Fatalf("Failed create: %s", err)
}
if ms.releases[k].Name != k {
t.Errorf("Unexpected release name: %s", ms.releases[k].Name)
}
}
func TestRead(t *testing.T) {
k := "test-1"
r := &release.Release{Name: k}
ms := NewMemory()
ms.Create(r)
if out, err := ms.Read(k); err != nil {
t.Errorf("Could not get %s: %s", k, err)
} else if out.Name != k {
t.Errorf("Expected %s, got %s", k, out.Name)
}
}
func TestHistory(t *testing.T) {
k := "test-1"
r := &release.Release{Name: k}
ms := NewMemory()
ms.Create(r)
if out, err := ms.History(k); err != nil {
t.Errorf("Could not get %s: %s", k, err)
} else if len(out) != 1 {
t.Fatalf("Expected 1 release, got %d", len(out))
} else if out[0].Name != k {
t.Errorf("Expected %s, got %s", k, out[0].Name)
}
}
func TestUpdate(t *testing.T) {
k := "test-1"
r := &release.Release{Name: k}
ms := NewMemory()
if err := ms.Create(r); err != nil {
t.Fatalf("Failed create: %s", err)
}
if err := ms.Update(r); err != nil {
t.Fatalf("Failed update: %s", err)
}
if ms.releases[k].Name != k {
t.Errorf("Unexpected release name: %s", ms.releases[k].Name)
}
}
func TestList(t *testing.T) {
ms := NewMemory()
rels := []string{"a", "b", "c"}
for _, k := range rels {
ms.Create(&release.Release{
Name: k,
Info: &release.Info{
Status: &release.Status{Code: release.Status_UNKNOWN},
},
})
ms.Create(&release.Release{
Name: "deleted-should-not-show-up",
Info: &release.Info{
Status: &release.Status{Code: release.Status_DELETED},
},
})
}
l, err := ms.List()
if err != nil {
t.Error(err)
}
if len(l) != 3 {
t.Errorf("Expected 3, got %d", len(l))
}
for _, n := range rels {
foundN := false
for _, rr := range l {
if rr.Name == n {
foundN = true
break
}
}
if !foundN {
t.Errorf("Did not find %s in list.", n)
}
}
}
func TestQuery(t *testing.T) {
t.Skip("Not Implemented")
}

@ -0,0 +1,48 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 storage // import "k8s.io/helm/pkg/storage"
import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/storage/driver"
)
type Storage struct {
drv driver.Driver
}
func (st *Storage) StoreRelease(rls *rspb.Release) error {
return st.drv.Create(rls)
}
func (st *Storage) UpdateRelease(rls *rspb.Release) error {
return st.drv.Update(rls)
}
func (st *Storage) QueryRelease(key string) (*rspb.Release, error) {
return st.drv.Get(key)
}
func (st *Storage) DeleteRelease(key string) (*rspb.Release, error) {
return st.drv.Delete(key)
}
func Init(drv driver.Driver) *Storage {
if drv == nil {
drv = driver.NewMemory()
}
return &Storage{drv: drv}
}

@ -0,0 +1,141 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 storage // import "k8s.io/helm/pkg/storage"
import (
"fmt"
"reflect"
"testing"
"time"
rspb "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/storage/driver"
tspb "github.com/golang/protobuf/ptypes"
)
var storage = Init(driver.NewMemory())
func releaseData() *rspb.Release {
var manifest = `apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-storage-test
data:
count: "100"
limit: "200"
state: "new"
token: "abc"
`
tm, _ := tspb.TimestampProto(time.Now())
return &rspb.Release{
Name: "hungry-hippo",
Info: &rspb.Info{
FirstDeployed: tm,
LastDeployed: tm,
Status: &rspb.Status{Code: rspb.Status_DEPLOYED},
},
Version: 2,
Manifest: manifest,
Namespace: "kube-system",
}
}
func TestStoreRelease(t *testing.T) {
ckerr := func(err error, msg string) {
if err != nil {
t.Fatalf(fmt.Sprintf("Failed to %s: %q", msg, err))
}
}
rls := releaseData()
ckerr(storage.StoreRelease(rls), "StoreRelease")
res, err := storage.QueryRelease(rls.Name)
ckerr(err, "QueryRelease")
if !reflect.DeepEqual(rls, res) {
t.Fatalf("Expected %q, got %q", rls, res)
}
}
func TestQueryRelease(t *testing.T) {
ckerr := func(err error, msg string) {
if err != nil {
t.Fatalf(fmt.Sprintf("Failed to %s: %q", msg, err))
}
}
rls := releaseData()
ckerr(storage.StoreRelease(rls), "StoreRelease")
res, err := storage.QueryRelease(rls.Name)
ckerr(err, "QueryRelease")
if !reflect.DeepEqual(rls, res) {
t.Fatalf("Expected %q, got %q", rls, res)
}
}
func TestDeleteRelease(t *testing.T) {
ckerr := func(err error, msg string) {
if err != nil {
t.Fatalf(fmt.Sprintf("Failed to %s: %q", msg, err))
}
}
rls := releaseData()
ckerr(storage.StoreRelease(rls), "StoreRelease")
res, err := storage.DeleteRelease(rls.Name)
ckerr(err, "DeleteRelease")
if !reflect.DeepEqual(rls, res) {
t.Fatalf("Expected %q, got %q", rls, res)
}
}
func TestUpdateRelease(t *testing.T) {
ckeql := func(got, want interface{}, msg string) {
if !reflect.DeepEqual(got, want) {
t.Fatalf(fmt.Sprintf("%s: got %T, want %T", msg, got, want))
}
}
ckerr := func(err error, msg string) {
if err != nil {
t.Fatalf(fmt.Sprintf("Failed to %s: %q", msg, err))
}
}
rls := releaseData()
ckerr(storage.StoreRelease(rls), "StoreRelease")
rls.Name = "hungry-hippo"
rls.Version = 2
rls.Manifest = "old-manifest"
err := storage.UpdateRelease(rls)
ckerr(err, "UpdateRelease")
res, err := storage.QueryRelease(rls.Name)
ckerr(err, "QueryRelease")
ckeql(res, rls, "Expected Release")
ckeql(res.Name, rls.Name, "Expected Name")
ckeql(res.Version, rls.Version, "Expected Version")
ckeql(res.Manifest, rls.Manifest, "Expected Manifest")
}
Loading…
Cancel
Save