Skip to content

Commit

Permalink
Merge pull request helm#1007 from fibonacci1729/feat/storage-memory
Browse files Browse the repository at this point in the history
feat(storage): in-memory & configmaps driver
  • Loading branch information
fibonacci1729 authored Aug 10, 2016
2 parents ae4ff5c + ae2d6c5 commit 1b15275
Show file tree
Hide file tree
Showing 16 changed files with 1,141 additions and 327 deletions.
79 changes: 25 additions & 54 deletions cmd/tiller/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ import (
"k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
)

// UseConfigMaps is a feature flags to toggle use of configmaps storage driver.
const UseConfigMaps = false

// TillerNamespace is the namespace tiller is running in.
const TillerNamespace = "kube-system"

// GoTplEngine is the name of the Go template engine, as registered in the EngineYard.
const GoTplEngine = "gotpl"

Expand Down Expand Up @@ -85,56 +91,6 @@ type Engine interface {
Render(*chart.Chart, chartutil.Values) (map[string]string, error)
}

// ReleaseStorage represents a storage engine for a Release.
//
// Release storage must be concurrency safe.
type ReleaseStorage interface {

// Create stores a release in the storage.
//
// If a release with the same name exists, this returns an error.
//
// It may return other errors in cases where it cannot write to storage.
Create(*release.Release) error
// Read takes a name and returns a release that has that name.
//
// It will only return releases that are not deleted and not superseded.
//
// It will return an error if no relevant release can be found, or if storage
// is not properly functioning.
Read(name string) (*release.Release, error)

// Update looks for a release with the same name and updates it with the
// present release contents.
//
// For immutable storage backends, this may result in a new release record
// being created, and the previous release being marked as superseded.
//
// It will return an error if a previous release is not found. It may also
// return an error if the storage backend encounters an error.
Update(*release.Release) error

// Delete marks a Release as deleted.
//
// It returns the deleted record. If the record is not found or if the
// underlying storage encounters an error, this will return an error.
Delete(name string) (*release.Release, error)

// List lists all active (non-deleted, non-superseded) releases.
//
// To get deleted or superseded releases, use Query.
List() ([]*release.Release, error)

// Query takes a map of labels and returns any releases that match.
//
// Query will search all releases, including deleted and superseded ones.
// The provided map will be used to filter results.
Query(map[string]string) ([]*release.Release, error)

// History takes a release name and returns the history of releases.
History(name string) ([]*release.Release, error)
}

// KubeClient represents a client capable of communicating with the Kubernetes API.
//
// A KubeClient must be concurrency safe.
Expand Down Expand Up @@ -211,7 +167,7 @@ type Environment struct {
// EngineYard provides access to the known template engines.
EngineYard EngineYard
// Releases stores records of releases.
Releases ReleaseStorage
Releases *storage.Storage
// KubeClient is a Kubernetes API client.
KubeClient KubeClient
}
Expand All @@ -224,9 +180,24 @@ func New() *Environment {
// we can easily add some here.
GoTplEngine: e,
}

kbc := kube.New(nil)

var sd *storage.Storage
if UseConfigMaps {
c, err := kbc.Client()
if err != nil {
// panic because we cant initliaze driver with no client
panic(err)
}
sd = storage.Init(driver.NewConfigMaps(c.ConfigMaps(TillerNamespace)))
} else {
sd = storage.Init(driver.NewMemory())
}

return &Environment{
EngineYard: ey,
Releases: storage.NewMemory(),
KubeClient: kube.New(nil), //&PrintingKubeClient{Out: os.Stdout},
Releases: sd, //storage.Init(driver.NewMemory()),
KubeClient: kbc, //kube.New(nil), //&PrintingKubeClient{Out: os.Stdout},
}
}
15 changes: 9 additions & 6 deletions cmd/tiller/environment/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
)

type mockEngine struct {
Expand All @@ -38,12 +40,14 @@ type mockReleaseStorage struct {
rel *release.Release
}

var _ driver.Driver = (*mockReleaseStorage)(nil)

func (r *mockReleaseStorage) Create(v *release.Release) error {
r.rel = v
return nil
}

func (r *mockReleaseStorage) Read(k string) (*release.Release, error) {
func (r *mockReleaseStorage) Get(k string) (*release.Release, error) {
return r.rel, nil
}

Expand All @@ -56,7 +60,7 @@ func (r *mockReleaseStorage) Delete(k string) (*release.Release, error) {
return r.rel, nil
}

func (r *mockReleaseStorage) List() ([]*release.Release, error) {
func (r *mockReleaseStorage) List(func(*release.Release) bool) ([]*release.Release, error) {
return []*release.Release{}, nil
}

Expand All @@ -66,7 +70,7 @@ func (r *mockReleaseStorage) Query(labels map[string]string) ([]*release.Release

func (r *mockReleaseStorage) History(n string) ([]*release.Release, error) {
res := []*release.Release{}
rel, err := r.Read(n)
rel, err := r.Get(n)
if err != nil {
return res, err
}
Expand All @@ -91,7 +95,6 @@ func (k *mockKubeClient) WatchUntilReady(ns string, r io.Reader) error {
}

var _ Engine = &mockEngine{}
var _ ReleaseStorage = &mockReleaseStorage{}
var _ KubeClient = &mockKubeClient{}
var _ KubeClient = &PrintingKubeClient{}

Expand All @@ -113,7 +116,7 @@ func TestEngine(t *testing.T) {
func TestReleaseStorage(t *testing.T) {
rs := &mockReleaseStorage{}
env := New()
env.Releases = rs
env.Releases = storage.Init(rs)

release := &release.Release{Name: "mariner"}

Expand All @@ -125,7 +128,7 @@ func TestReleaseStorage(t *testing.T) {
t.Fatalf("failed to update release: %s", err)
}

if v, err := env.Releases.Read("albatross"); err != nil {
if v, err := env.Releases.Get("albatross"); err != nil {
t.Errorf("Error fetching release: %s", err)
} else if v.Name != "mariner" {
t.Errorf("Expected mariner, got %q", v.Name)
Expand Down
16 changes: 8 additions & 8 deletions cmd/tiller/release_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv"
)

Expand Down Expand Up @@ -61,7 +61,7 @@ type releaseServer struct {
}

func (s *releaseServer) ListReleases(req *services.ListReleasesRequest, stream services.ReleaseService_ListReleasesServer) error {
rels, err := s.env.Releases.List()
rels, err := s.env.Releases.ListDeployed()
if err != nil {
return err
}
Expand Down Expand Up @@ -151,7 +151,7 @@ func (s *releaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease
if req.Name == "" {
return nil, errMissingRelease
}
rel, err := s.env.Releases.Read(req.Name)
rel, err := s.env.Releases.Get(req.Name)
if err != nil {
return nil, err
}
Expand All @@ -165,7 +165,7 @@ func (s *releaseServer) GetReleaseContent(c ctx.Context, req *services.GetReleas
if req.Name == "" {
return nil, errMissingRelease
}
rel, err := s.env.Releases.Read(req.Name)
rel, err := s.env.Releases.Get(req.Name)
return &services.GetReleaseContentResponse{Release: rel}, err
}

Expand Down Expand Up @@ -232,7 +232,7 @@ func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
}

// finds the non-deleted release with the given name
currentRelease, err := s.env.Releases.Read(req.Name)
currentRelease, err := s.env.Releases.Get(req.Name)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -279,7 +279,7 @@ func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
// is granted. If reuse is true and a deleted release with that name exists,
// we re-grant it. Otherwise, an error is returned.
if start != "" {
if rel, err := s.env.Releases.Read(start); err == storage.ErrNotFound {
if rel, err := s.env.Releases.Get(start); err == driver.ErrReleaseNotFound {
return start, nil
} else if st := rel.Info.Status.Code; reuse && (st == release.Status_DELETED || st == release.Status_FAILED) {
// Allowe re-use of names if the previous release is marked deleted.
Expand All @@ -296,7 +296,7 @@ func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
for i := 0; i < maxTries; i++ {
namer := moniker.New()
name := namer.NameSep("-")
if _, err := s.env.Releases.Read(name); err == storage.ErrNotFound {
if _, err := s.env.Releases.Get(name); err == driver.ErrReleaseNotFound {
return name, nil
}
log.Printf("info: Name %q is taken. Searching again.", name)
Expand Down Expand Up @@ -498,7 +498,7 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return nil, errMissingRelease
}

rel, err := s.env.Releases.Read(req.Name)
rel, err := s.env.Releases.Get(req.Name)
if err != nil {
log.Printf("uninstall: Release not loaded: %s", req.Name)
return nil, err
Expand Down
9 changes: 5 additions & 4 deletions cmd/tiller/release_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
)

var manifestWithHook = `apiVersion: v1
Expand Down Expand Up @@ -176,7 +177,7 @@ func TestInstallRelease(t *testing.T) {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
}

rel, err := rs.env.Releases.Read(res.Release.Name)
rel, err := rs.env.Releases.Get(res.Release.Name)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
Expand Down Expand Up @@ -246,7 +247,7 @@ func TestInstallReleaseDryRun(t *testing.T) {
t.Errorf("Should not contain template data for an empty file. %s", res.Release.Manifest)
}

if _, err := rs.env.Releases.Read(res.Release.Name); err == nil {
if _, err := rs.env.Releases.Get(res.Release.Name); err == nil {
t.Errorf("Expected no stored release.")
}

Expand Down Expand Up @@ -333,7 +334,7 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
}

updated, err := rs.env.Releases.Read(res.Release.Name)
updated, err := rs.env.Releases.Get(res.Release.Name)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
Expand Down Expand Up @@ -597,7 +598,7 @@ func TestListReleasesFilter(t *testing.T) {

func mockEnvironment() *environment.Environment {
e := environment.New()
e.Releases = storage.NewMemory()
e.Releases = storage.Init(driver.NewMemory())
e.KubeClient = &environment.PrintingKubeClient{Out: os.Stdout}
return e
}
Expand Down
2 changes: 0 additions & 2 deletions cmd/tiller/tiller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ import (

"k8s.io/helm/cmd/tiller/environment"
"k8s.io/helm/pkg/engine"
"k8s.io/helm/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 TestInit(t *testing.T) {
defer func() {
Expand Down
9 changes: 4 additions & 5 deletions pkg/storage/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/*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 implements storage for Tiller objects.The backend storage
mechanism may be implemented with different backends. This package and its
subpackages provide storage layers for Tiller objects.
*/
package storage // import "k8s.io/helm/pkg/storage"
Loading

0 comments on commit 1b15275

Please sign in to comment.