Commit ffa38d16 authored by Matt Butcher's avatar Matt Butcher

Merge pull request #14 from technosophos/feat/release-storage

feat(storage): add basic implementation of storage
parents 5f1803fe 44dc0de7
......@@ -3,15 +3,24 @@ package environment
import (
"github.com/deis/tiller/pkg/engine"
"github.com/deis/tiller/pkg/hapi"
"github.com/deis/tiller/pkg/storage"
)
// GoTplEngine is the name of the Go template engine, as registered in the EngineYard.
const GoTplEngine = "gotpl"
// DefaultEngine points to the engine that the EngineYard should treat as the
// default. A chart that does not specify an engine may be run through the
// default engine.
var DefaultEngine = GoTplEngine
// EngineYard maps engine names to engine implementations.
type EngineYard map[string]Engine
// Get retrieves a template engine by name.
//
// If no matching template engine is found, the second return value will
// be false.
func (y EngineYard) Get(k string) (Engine, bool) {
e, ok := y[k]
return e, ok
......@@ -49,8 +58,16 @@ type Engine interface {
//
// Release storage must be concurrency safe.
type ReleaseStorage interface {
// Get takes a name and returns the accompanying release.
Get(key string) (*hapi.Release, error)
// Set saves the release with the given name.
Set(key string, val *hapi.Release) error
// List lists all active (non-deleted, non-superseded) releases.
//
// To get deleted or superseded releases, use Query.
List() ([]*hapi.Release, error)
// Query takes a map of labels and returns any releases that match.
Query(map[string]string) ([]*hapi.Release, error)
}
// KubeClient represents a client capable of communicating with the Kubernetes API.
......@@ -81,8 +98,13 @@ type Environment struct {
// New returns an environment initialized with the defaults.
func New() *Environment {
e := engine.New()
var ey EngineYard = map[string]Engine{GoTplEngine: e}
var ey EngineYard = map[string]Engine{
// Currently, the only template engine we support is the GoTpl one. But
// we can easily add some here.
GoTplEngine: e,
}
return &Environment{
EngineYard: ey,
Releases: storage.NewMemory(),
}
}
......@@ -27,6 +27,14 @@ func (r *mockReleaseStorage) Set(k string, v *hapi.Release) error {
return nil
}
func (r *mockReleaseStorage) List() ([]*hapi.Release, error) {
return []*hapi.Release{}, nil
}
func (r *mockReleaseStorage) Query(labels map[string]string) ([]*hapi.Release, error) {
return []*hapi.Release{}, nil
}
type mockKubeClient struct {
}
......
......@@ -5,11 +5,13 @@ import (
"github.com/deis/tiller/cmd/tiller/environment"
"github.com/deis/tiller/pkg/engine"
"github.com/deis/tiller/pkg/storage"
)
// These are canary tests to make sure that the default server actually
// fulfills its requirements.
var _ environment.Engine = &engine.Engine{}
var _ environment.ReleaseStorage = storage.NewMemory()
func TestNewServer(t *testing.T) {
defer func() {
......
......@@ -9,7 +9,10 @@ import (
"github.com/deis/tiller/pkg/hapi"
)
// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
// FuncMap contains the template functions that will be passed to each
// render call. This may only be modified before the first call to Render.
FuncMap template.FuncMap
}
......
/*Package storage implements storage for Tiller objects.
Tiller stores releases (see 'cmd/tiller/environment'.Environment). The backend
storage mechanism may be implemented with different backends. This package
and its subpackages provide storage layers for Tiller objects.
*/
package storage
package storage
import (
"errors"
"github.com/deis/tiller/pkg/hapi"
)
// Memory is an in-memory ReleaseStorage implementation.
type Memory struct {
releases map[string]*hapi.Release
}
func NewMemory() *Memory {
return &Memory{
releases: map[string]*hapi.Release{},
}
}
var ErrNotFound = errors.New("release not found")
// Get returns the named Release.
//
// If the release is not found, an ErrNotFound error is returned.
func (m *Memory) Get(k string) (*hapi.Release, error) {
v, ok := m.releases[k]
if !ok {
return v, ErrNotFound
}
return v, nil
}
// Set sets a release.
//
// TODO: Is there any reason why Set doesn't just use the release name?
func (m *Memory) Set(k string, rel *hapi.Release) error {
m.releases[k] = rel
return nil
}
// List returns all releases
func (m *Memory) List() ([]*hapi.Release, error) {
buf := make([]*hapi.Release, len(m.releases))
i := 0
for _, v := range m.releases {
buf[i] = v
i++
}
return buf, nil
}
func (m *Memory) Query(labels map[string]string) ([]*hapi.Release, error) {
return []*hapi.Release{}, errors.New("Cannot implement until hapi.Release is defined.")
}
package storage
import (
"testing"
"github.com/deis/tiller/pkg/hapi"
)
func TestSet(t *testing.T) {
k := "test-1"
r := &hapi.Release{Name: k}
ms := NewMemory()
if err := ms.Set(k, r); err != nil {
t.Fatalf("Failed set: %s", err)
}
if ms.releases[k].Name != k {
t.Errorf("Unexpected release name: %s", ms.releases[k].Name)
}
}
func TestGet(t *testing.T) {
k := "test-1"
r := &hapi.Release{Name: k}
ms := NewMemory()
ms.Set(k, r)
if out, err := ms.Get(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 TestList(t *testing.T) {
ms := NewMemory()
rels := []string{"a", "b", "c"}
for _, k := range rels {
ms.Set(k, &hapi.Release{Name: k})
}
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")
}
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