From 9281012d3cf9e8ea1b92815738f1f0a03d152e87 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Tue, 12 Apr 2016 13:42:27 -0700 Subject: [PATCH 1/6] feat(helm): add init cmd and test --- cmd/helm/init.go | 7 +++++-- cmd/helm/init_test.go | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 cmd/helm/init_test.go diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 5679de8e2..2565f34dd 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "github.com/spf13/cobra" @@ -14,9 +15,11 @@ var initCmd = &cobra.Command{ Use: "init", Short: "Initialize Helm on both client and server.", Long: `Add long help here`, - Run: runInit, + RunE: RunInit, } -func runInit(cmd *cobra.Command, args []string) { +// RunInit initializes local config and installs tiller to Kubernetes Cluster +func RunInit(cmd *cobra.Command, args []string) error { fmt.Fprintln(stdout, "Init was called.") + return errors.New("NotImplemented") } diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go new file mode 100644 index 000000000..333714ad0 --- /dev/null +++ b/cmd/helm/init_test.go @@ -0,0 +1,14 @@ +package main + +import ( + "testing" +) + +func TestRunInit(t *testing.T) { + + //TODO: call command and make sure no error is recevied + err := RunInit(initCmd, nil) + if err != nil { + t.Errorf("Expected no error but got one: %s", err) + } +} From 338dc6d4feeded97669a1a7e3e9233e07641a793 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Tue, 12 Apr 2016 16:08:22 -0700 Subject: [PATCH 2/6] feat(init): add Dockerfile for tiller --- cmd/tiller/.dockerignore | 3 +++ cmd/tiller/Dockerfile | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 cmd/tiller/.dockerignore create mode 100644 cmd/tiller/Dockerfile diff --git a/cmd/tiller/.dockerignore b/cmd/tiller/.dockerignore new file mode 100644 index 000000000..f6fb65317 --- /dev/null +++ b/cmd/tiller/.dockerignore @@ -0,0 +1,3 @@ +.dockerignore +Dockerfile +Makefile diff --git a/cmd/tiller/Dockerfile b/cmd/tiller/Dockerfile new file mode 100644 index 000000000..eba2c76af --- /dev/null +++ b/cmd/tiller/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:14.04 + +ADD . / + +CMD ["/tiller"] From 274067a2b4c13e711707a9b5538c644319dfa65c Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Thu, 14 Apr 2016 14:38:00 -0600 Subject: [PATCH 3/6] ref(Makefile): add default registry + "/"s --- Makefile | 4 ++-- versioning.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 308737dcb..e80d68faa 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -DOCKER_REGISTRY := -IMAGE_PREFIX ?= helm +DOCKER_REGISTRY ?= gcr.io +IMAGE_PREFIX ?= deis-sandbox SHORT_NAME ?= tiller # go option diff --git a/versioning.mk b/versioning.mk index 2faa2ec6f..8d96c8629 100644 --- a/versioning.mk +++ b/versioning.mk @@ -1,8 +1,8 @@ MUTABLE_VERSION ?= canary VERSION ?= git-$(shell git rev-parse --short HEAD) -IMAGE := ${DOCKER_REGISTRY}${IMAGE_PREFIX}/${SHORT_NAME}:${VERSION} -MUTABLE_IMAGE := ${DOCKER_REGISTRY}${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION} +IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${VERSION} +MUTABLE_IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION} info: @echo "Build tag: ${VERSION}" From 72acb82e5002dbb7c8e72d75551b3e9d72e862b5 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Thu, 14 Apr 2016 14:39:32 -0600 Subject: [PATCH 4/6] feat(init): add tiller installer logic --- pkg/client/install.go | 91 +++++++++++++++++++++++++++++++++++++ pkg/kubectl/command.go | 32 +++++++++++++ pkg/kubectl/create.go | 21 +++++++++ pkg/kubectl/create_test.go | 22 +++++++++ pkg/kubectl/kubectl.go | 19 ++++++++ pkg/kubectl/kubectl_test.go | 12 +++++ 6 files changed, 197 insertions(+) create mode 100644 pkg/client/install.go create mode 100644 pkg/kubectl/command.go create mode 100644 pkg/kubectl/create.go create mode 100644 pkg/kubectl/create_test.go create mode 100644 pkg/kubectl/kubectl.go create mode 100644 pkg/kubectl/kubectl_test.go diff --git a/pkg/client/install.go b/pkg/client/install.go new file mode 100644 index 000000000..1861727e2 --- /dev/null +++ b/pkg/client/install.go @@ -0,0 +1,91 @@ +package client + +import ( + "bytes" + "text/template" + + "github.com/Masterminds/sprig" + "github.com/deis/tiller/pkg/kubectl" +) + +// Installer installs tiller into Kubernetes +// +// See InstallYAML. +type Installer struct { + + // Metadata holds any global metadata attributes for the resources + Metadata map[string]interface{} + + // Tiller specific metadata + Tiller map[string]interface{} +} + +// New Installer creates a new Installer +func NewInstaller() *Installer { + return &Installer{ + Metadata: map[string]interface{}{}, + Tiller: map[string]interface{}{}, + } +} + +// Install uses kubectl to install tiller +// +// Returns the string output received from the operation, and an error if the +// command failed. +func (i *Installer) Install(runner kubectl.Runner) (string, error) { + b, err := i.expand() + if err != nil { + return "", err + } + + o, err := runner.Create(b) + return string(o), err +} + +func (i *Installer) expand() ([]byte, error) { + var b bytes.Buffer + t := template.Must(template.New("manifest").Funcs(sprig.TxtFuncMap()).Parse(InstallYAML)) + err := t.Execute(&b, i) + return b.Bytes(), err +} + +// InstallYAML is the installation YAML for DM. +const InstallYAML = ` +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + app: helm + name: helm-namespace + name: helm +--- +apiVersion: v1 +kind: ReplicationController +metadata: + labels: + app: helm + name: tiller + name: tiller-rc + namespace: helm +spec: + replicas: 1 + selector: + app: helm + name: tiller + template: + metadata: + labels: + app: helm + name: tiller + spec: + containers: + - env: [] + image: {{default "gcr.io/deis-sandbox/tiller:canary" .Tiller.Image}} + name: tiller + ports: + - containerPort: 8080 + name: tiller + imagePullPolicy: Always +--- +` diff --git a/pkg/kubectl/command.go b/pkg/kubectl/command.go new file mode 100644 index 000000000..b36e0ad33 --- /dev/null +++ b/pkg/kubectl/command.go @@ -0,0 +1,32 @@ +package kubectl + +import ( + "bytes" + "fmt" + "io/ioutil" + "os/exec" + "strings" +) + +type cmd struct { + *exec.Cmd +} + +func command(args ...string) *cmd { + return &cmd{exec.Command(Path, args...)} +} + +func assignStdin(cmd *cmd, in []byte) { + cmd.Stdin = bytes.NewBuffer(in) +} + +func (c *cmd) String() string { + var stdin string + + if c.Stdin != nil { + b, _ := ioutil.ReadAll(c.Stdin) + stdin = fmt.Sprintf("< %s", string(b)) + } + + return fmt.Sprintf("[CMD] %s %s", strings.Join(c.Args, " "), stdin) +} diff --git a/pkg/kubectl/create.go b/pkg/kubectl/create.go new file mode 100644 index 000000000..af9297aa9 --- /dev/null +++ b/pkg/kubectl/create.go @@ -0,0 +1,21 @@ +package kubectl + +// Create uploads a chart to Kubernetes +func (r RealRunner) Create(stdin []byte) ([]byte, error) { + args := []string{"create", "-f", "-"} + + cmd := command(args...) + assignStdin(cmd, stdin) + + return cmd.CombinedOutput() +} + +// Create returns the commands to kubectl +func (r PrintRunner) Create(stdin []byte) ([]byte, error) { + args := []string{"create", "-f", "-"} + + cmd := command(args...) + assignStdin(cmd, stdin) + + return []byte(cmd.String()), nil +} diff --git a/pkg/kubectl/create_test.go b/pkg/kubectl/create_test.go new file mode 100644 index 000000000..bca94f6e5 --- /dev/null +++ b/pkg/kubectl/create_test.go @@ -0,0 +1,22 @@ +package kubectl + +import ( + "testing" +) + +func TestPrintCreate(t *testing.T) { + var client Runner = PrintRunner{} + + expected := `[CMD] kubectl create -f - < some stdin data` + + out, err := client.Create([]byte("some stdin data")) + if err != nil { + t.Error(err) + } + + actual := string(out) + + if expected != actual { + t.Fatalf("actual %s != expected %s", actual, expected) + } +} diff --git a/pkg/kubectl/kubectl.go b/pkg/kubectl/kubectl.go new file mode 100644 index 000000000..e527b71fe --- /dev/null +++ b/pkg/kubectl/kubectl.go @@ -0,0 +1,19 @@ +package kubectl + +// Path is the path of the kubectl binary +var Path = "kubectl" + +// Runner is an interface to wrap kubectl convenience methods +type Runner interface { + // Create uploads a chart to Kubernetes + Create(stdin []byte) ([]byte, error) +} + +// RealRunner implements Runner to execute kubectl commands +type RealRunner struct{} + +// PrintRunner implements Runner to return a []byte of the command to be executed +type PrintRunner struct{} + +// Client stores the instance of Runner +var Client Runner = RealRunner{} diff --git a/pkg/kubectl/kubectl_test.go b/pkg/kubectl/kubectl_test.go new file mode 100644 index 000000000..c3348bba5 --- /dev/null +++ b/pkg/kubectl/kubectl_test.go @@ -0,0 +1,12 @@ +package kubectl + +type TestRunner struct { + Runner + + out []byte + err error +} + +func (r TestRunner) Create(stdin []byte, ns string) ([]byte, error) { + return r.out, r.err +} From 306aca6aec4961c77ce12ab00ee414919dffeb33 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Thu, 14 Apr 2016 14:40:10 -0600 Subject: [PATCH 5/6] feat(init): add init logic + -i flag to override tiller image --- cmd/helm/init.go | 31 +++++++++++++++++++++++++++++-- cmd/helm/init_test.go | 10 +++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 2565f34dd..1074afc82 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -4,10 +4,15 @@ import ( "errors" "fmt" + "github.com/deis/tiller/pkg/client" + "github.com/deis/tiller/pkg/kubectl" "github.com/spf13/cobra" ) +var tillerImg string + func init() { + initCmd.Flags().StringVarP(&tillerImg, "tiller-image", "i", "", "override tiller image") RootCommand.AddCommand(initCmd) } @@ -20,6 +25,28 @@ var initCmd = &cobra.Command{ // RunInit initializes local config and installs tiller to Kubernetes Cluster func RunInit(cmd *cobra.Command, args []string) error { - fmt.Fprintln(stdout, "Init was called.") - return errors.New("NotImplemented") + if len(args) != 0 { + return errors.New("This command does not accept arguments. \n") + } + + // TODO: take value of global flag kubectl and pass that in + runner := buildKubectlRunner("") + + i := client.NewInstaller() + i.Tiller["Image"] = tillerImg + + out, err := i.Install(runner) + if err != nil { + return fmt.Errorf("error installing %s %s", string(out), err) + } + + fmt.Printf("Tiller (the helm server side component) has been installed into your Kubernetes Cluster.\n") + return nil +} + +func buildKubectlRunner(kubectlPath string) kubectl.Runner { + if kubectlPath != "" { + kubectl.Path = kubectlPath + } + return &kubectl.RealRunner{} } diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index 333714ad0..59a45c6ab 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -4,11 +4,7 @@ import ( "testing" ) -func TestRunInit(t *testing.T) { - - //TODO: call command and make sure no error is recevied - err := RunInit(initCmd, nil) - if err != nil { - t.Errorf("Expected no error but got one: %s", err) - } +func TestInit(t *testing.T) { + //TODO: call command and make sure no error is returned + //TODO: check local config } From 40cbc9007c0e5f68a0058e13ada3f6c7382432c9 Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Thu, 14 Apr 2016 14:55:05 -0600 Subject: [PATCH 6/6] ref(init): add desc, rm cmd/tiller/Dockerfile --- cmd/helm/init.go | 7 ++++++- cmd/tiller/.dockerignore | 3 --- cmd/tiller/Dockerfile | 5 ----- 3 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 cmd/tiller/.dockerignore delete mode 100644 cmd/tiller/Dockerfile diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 1074afc82..062f6d6b4 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -9,6 +9,11 @@ import ( "github.com/spf13/cobra" ) +const longDesc = ` +This command installs Tiller (the helm server side component) onto your +Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.helm/) +` + var tillerImg string func init() { @@ -19,7 +24,7 @@ func init() { var initCmd = &cobra.Command{ Use: "init", Short: "Initialize Helm on both client and server.", - Long: `Add long help here`, + Long: longDesc, RunE: RunInit, } diff --git a/cmd/tiller/.dockerignore b/cmd/tiller/.dockerignore deleted file mode 100644 index f6fb65317..000000000 --- a/cmd/tiller/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.dockerignore -Dockerfile -Makefile diff --git a/cmd/tiller/Dockerfile b/cmd/tiller/Dockerfile deleted file mode 100644 index eba2c76af..000000000 --- a/cmd/tiller/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:14.04 - -ADD . / - -CMD ["/tiller"]