mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
Merge pull request #1057 from technosophos/feat/configmaps-default
feat(tiller): make configmaps the default storage
This commit is contained in:
commit
120256ecb3
9 changed files with 96 additions and 21 deletions
|
|
@ -23,6 +23,7 @@ These dependencies are expressed as interfaces so that alternate implementations
|
|||
package environment
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"k8s.io/helm/pkg/chartutil"
|
||||
|
|
@ -31,11 +32,9 @@ import (
|
|||
"k8s.io/helm/pkg/proto/hapi/chart"
|
||||
"k8s.io/helm/pkg/storage"
|
||||
"k8s.io/helm/pkg/storage/driver"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned"
|
||||
)
|
||||
|
||||
// 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"
|
||||
|
||||
|
|
@ -135,6 +134,9 @@ type KubeClient interface {
|
|||
// reader must contain a YAML stream (one or more YAML documents separated
|
||||
// by "\n---\n").
|
||||
Update(namespace string, originalReader, modifiedReader io.Reader) error
|
||||
|
||||
// APIClient gets a raw API client for Kubernetes.
|
||||
APIClient() (unversioned.Interface, error)
|
||||
}
|
||||
|
||||
// PrintingKubeClient implements KubeClient, but simply prints the reader to
|
||||
|
|
@ -143,6 +145,14 @@ type PrintingKubeClient struct {
|
|||
Out io.Writer
|
||||
}
|
||||
|
||||
// APIClient always returns an error.
|
||||
//
|
||||
// The printing client does not have access to a Kubernetes client at all. So it
|
||||
// will always return an error if the client is accessed.
|
||||
func (p *PrintingKubeClient) APIClient() (unversioned.Interface, error) {
|
||||
return nil, errors.New("no API client found")
|
||||
}
|
||||
|
||||
// Create prints the values of what would be created with a real KubeClient.
|
||||
func (p *PrintingKubeClient) Create(ns string, r io.Reader) error {
|
||||
_, err := io.Copy(p.Out, r)
|
||||
|
|
@ -196,23 +206,9 @@ func New() *Environment {
|
|||
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: sd, //storage.Init(driver.NewMemory()),
|
||||
KubeClient: kbc, //kube.New(nil), //&PrintingKubeClient{Out: os.Stdout},
|
||||
Releases: storage.Init(driver.NewMemory()),
|
||||
KubeClient: kube.New(nil),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import (
|
|||
"k8s.io/helm/pkg/proto/hapi/release"
|
||||
"k8s.io/helm/pkg/storage"
|
||||
"k8s.io/helm/pkg/storage/driver"
|
||||
unversionedclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
|
||||
)
|
||||
|
||||
type mockEngine struct {
|
||||
|
|
@ -47,6 +49,10 @@ func (r *mockReleaseStorage) Create(v *release.Release) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *mockReleaseStorage) Name() string {
|
||||
return "mockReleaseStorage"
|
||||
}
|
||||
|
||||
func (r *mockReleaseStorage) Get(k string) (*release.Release, error) {
|
||||
return r.rel, nil
|
||||
}
|
||||
|
|
@ -81,6 +87,10 @@ func (r *mockReleaseStorage) History(n string) ([]*release.Release, error) {
|
|||
type mockKubeClient struct {
|
||||
}
|
||||
|
||||
func (k *mockKubeClient) APIClient() (unversionedclient.Interface, error) {
|
||||
return testclient.NewSimpleFake(), nil
|
||||
}
|
||||
|
||||
func (k *mockKubeClient) Create(ns string, r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
|
||||
"k8s.io/helm/cmd/tiller/environment"
|
||||
"k8s.io/helm/pkg/storage"
|
||||
"k8s.io/helm/pkg/storage/driver"
|
||||
)
|
||||
|
||||
const (
|
||||
storageMemory = "memory"
|
||||
storageConfigMap = "configmap"
|
||||
)
|
||||
|
||||
// rootServer is the root gRPC server.
|
||||
|
|
@ -38,8 +45,11 @@ var rootServer = grpc.NewServer()
|
|||
// Any changes to env should be done before rootServer.Serve() is called.
|
||||
var env = environment.New()
|
||||
|
||||
var addr = ":44134"
|
||||
var probe = ":44135"
|
||||
var (
|
||||
addr = ":44134"
|
||||
probe = ":44135"
|
||||
store = storageConfigMap
|
||||
)
|
||||
|
||||
const globalUsage = `The Kubernetes Helm server.
|
||||
|
||||
|
|
@ -58,10 +68,22 @@ var rootCommand = &cobra.Command{
|
|||
func main() {
|
||||
pf := rootCommand.PersistentFlags()
|
||||
pf.StringVarP(&addr, "listen", "l", ":44134", "The address:port to listen on")
|
||||
pf.StringVar(&store, "storage", storageConfigMap, "The storage driver to use. One of 'configmap' or 'memory'")
|
||||
rootCommand.Execute()
|
||||
}
|
||||
|
||||
func start(c *cobra.Command, args []string) {
|
||||
switch store {
|
||||
case storageMemory:
|
||||
env.Releases = storage.Init(driver.NewMemory())
|
||||
case storageConfigMap:
|
||||
c, err := env.KubeClient.APIClient()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Cannot initialize Kubernetes connection: %s", err)
|
||||
}
|
||||
env.Releases = storage.Init(driver.NewConfigMaps(c.ConfigMaps(environment.TillerNamespace)))
|
||||
}
|
||||
|
||||
lstn, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Server died: %s\n", err)
|
||||
|
|
@ -70,6 +92,7 @@ func start(c *cobra.Command, args []string) {
|
|||
|
||||
fmt.Printf("Tiller is running on %s\n", addr)
|
||||
fmt.Printf("Tiller probes server is running on %s\n", probe)
|
||||
fmt.Printf("Storage driver is %s\n", env.Releases.Name())
|
||||
|
||||
srvErrCh := make(chan error)
|
||||
probeErrCh := make(chan error)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
unversionedclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
|
@ -54,6 +55,16 @@ func New(config clientcmd.ClientConfig) *Client {
|
|||
// ResourceActorFunc performs an action on a single resource.
|
||||
type ResourceActorFunc func(*resource.Info) error
|
||||
|
||||
// APIClient returns a Kubernetes API client.
|
||||
//
|
||||
// This is necessary because cmdutil.Client is a field, not a method, which
|
||||
// means it can't satisfy an interface's method requirement. In order to ensure
|
||||
// that an implementation of environment.KubeClient can access the raw API client,
|
||||
// it is necessary to add this method.
|
||||
func (c *Client) APIClient() (unversionedclient.Interface, error) {
|
||||
return c.Client()
|
||||
}
|
||||
|
||||
// Create creates kubernetes resources from an io.reader
|
||||
//
|
||||
// Namespace will set the namespace
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ import (
|
|||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
)
|
||||
|
||||
// ConfigMapsDriverName is the string name of the driver.
|
||||
const ConfigMapsDriverName = "ConfigMap"
|
||||
|
||||
var b64 = base64.StdEncoding
|
||||
|
||||
// labels is a map of key value pairs to be included as metadata in a configmap object.
|
||||
|
|
@ -54,6 +57,11 @@ func NewConfigMaps(impl client.ConfigMapsInterface) *ConfigMaps {
|
|||
return &ConfigMaps{impl: impl}
|
||||
}
|
||||
|
||||
// Name returns the name of the driver.
|
||||
func (cfgmaps *ConfigMaps) Name() string {
|
||||
return ConfigMapsDriverName
|
||||
}
|
||||
|
||||
// Get fetches the release named by key. The corresponding release is returned
|
||||
// or error if not found.
|
||||
func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ import (
|
|||
"k8s.io/kubernetes/pkg/client/unversioned"
|
||||
)
|
||||
|
||||
var _ Driver = &ConfigMaps{}
|
||||
|
||||
func TestConfigMapName(t *testing.T) {
|
||||
c := newTestFixture(t)
|
||||
if c.Name() != ConfigMapsDriverName {
|
||||
t.Errorf("Expected name to be %q, got %q", ConfigMapsDriverName, c.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigMapGet(t *testing.T) {
|
||||
key := "key-1"
|
||||
rel := newTestRelease(key, 1, rspb.Status_DEPLOYED)
|
||||
|
|
|
|||
|
|
@ -73,4 +73,5 @@ type Driver interface {
|
|||
Updator
|
||||
Deletor
|
||||
Queryor
|
||||
Name() string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ import (
|
|||
rspb "k8s.io/helm/pkg/proto/hapi/release"
|
||||
)
|
||||
|
||||
// MemoryDriverName is the string name of this driver.
|
||||
const MemoryDriverName = "Memory"
|
||||
|
||||
// Memory is the in-memory storage driver implementation.
|
||||
type Memory struct {
|
||||
sync.RWMutex
|
||||
|
|
@ -33,6 +36,11 @@ func NewMemory() *Memory {
|
|||
return &Memory{cache: map[string]*rspb.Release{}}
|
||||
}
|
||||
|
||||
// Name returns the name of the driver.
|
||||
func (mem *Memory) Name() string {
|
||||
return MemoryDriverName
|
||||
}
|
||||
|
||||
// Get returns the release named by key or returns ErrReleaseNotFound.
|
||||
func (mem *Memory) Get(key string) (*rspb.Release, error) {
|
||||
defer unlock(mem.rlock())
|
||||
|
|
|
|||
|
|
@ -23,6 +23,15 @@ import (
|
|||
rspb "k8s.io/helm/pkg/proto/hapi/release"
|
||||
)
|
||||
|
||||
var _ Driver = &Memory{}
|
||||
|
||||
func TestMemoryName(t *testing.T) {
|
||||
mem := NewMemory()
|
||||
if mem.Name() != MemoryDriverName {
|
||||
t.Errorf("Expected name to be %q, got %q", MemoryDriverName, mem.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemoryGet(t *testing.T) {
|
||||
key := "test-1"
|
||||
rls := &rspb.Release{Name: key}
|
||||
|
|
|
|||
Loading…
Reference in a new issue