mirror of https://github.com/helm/helm.git
fix(helm): add dry-run flag for init
This adds a --dry-run flag to init, and causes the manifest file for Tiller to be emitted on --debug. Together, this means you can do a 'helm init --dry-run --debug' and dump the Tiller manifest much as you can with 'helm install --dry-run --debug'. This does not require a server round-trip. Closes #1417
This commit is contained in:
parent
05c04bccae
commit
89c781582a
|
@ -33,7 +33,23 @@ import (
|
|||
|
||||
const initDesc = `
|
||||
This command installs Tiller (the helm server side component) onto your
|
||||
Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.helm/)
|
||||
Kubernetes Cluster and sets up local configuration in $HELM_HOME (default ~/.helm/)
|
||||
|
||||
As with the rest of the Helm commands, 'helm init' discovers Kubernetes clusters
|
||||
by reading $KUBECONFIG (default '~/.kube/config') and using the default context.
|
||||
|
||||
To set up just a local environment, use '--client-only'. That will configure
|
||||
$HELM_HOME, but not attempt to connect to a remote cluster and install the Tiller
|
||||
deployment.
|
||||
|
||||
When installing Tiller, 'helm init' will attempt to install the latest released
|
||||
version. You can specify an alternative image with '--tiller-image'. For those
|
||||
frequently working on the latest code, the flag '--canary-image' will install
|
||||
the latest pre-release version of Tiller (e.g. the HEAD commit in the GitHub
|
||||
repository on the master branch).
|
||||
|
||||
To dump a manifest containing the Tiller deployment YAML, combine the
|
||||
'--dry-run' and '--debug' flags.
|
||||
`
|
||||
|
||||
const (
|
||||
|
@ -47,6 +63,7 @@ type initCmd struct {
|
|||
image string
|
||||
clientOnly bool
|
||||
canary bool
|
||||
dryRun bool
|
||||
out io.Writer
|
||||
home helmpath.Home
|
||||
kubeClient unversioned.DeploymentsNamespacer
|
||||
|
@ -74,12 +91,25 @@ func newInitCmd(out io.Writer) *cobra.Command {
|
|||
f.StringVarP(&i.image, "tiller-image", "i", "", "override tiller image")
|
||||
f.BoolVar(&i.canary, "canary-image", false, "use the canary tiller image")
|
||||
f.BoolVarP(&i.clientOnly, "client-only", "c", false, "if set does not install tiller")
|
||||
f.BoolVar(&i.dryRun, "dry-run", false, "do not install local or remote")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// runInit initializes local config and installs tiller to Kubernetes Cluster
|
||||
func (i *initCmd) run() error {
|
||||
|
||||
if flagDebug {
|
||||
m, err := installer.DeploymentManifest(i.image, i.canary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(i.out, m)
|
||||
}
|
||||
if i.dryRun {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := ensureHome(i.home, i.out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
|
||||
|
@ -87,7 +89,7 @@ func TestInitCmd_clientOnly(t *testing.T) {
|
|||
fake := testclient.Fake{}
|
||||
cmd := &initCmd{out: &buf, home: helmpath.Home(home), kubeClient: fake.Extensions(), clientOnly: true}
|
||||
if err := cmd.run(); err != nil {
|
||||
t.Errorf("expected error: %v", err)
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if len(fake.Actions()) != 0 {
|
||||
t.Error("expected client call")
|
||||
|
@ -97,6 +99,42 @@ func TestInitCmd_clientOnly(t *testing.T) {
|
|||
t.Errorf("expected %q, got %q", expected, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitCmd_dryRun(t *testing.T) {
|
||||
// This is purely defensive in this case.
|
||||
home, err := ioutil.TempDir("", "helm_home")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dbg := flagDebug
|
||||
flagDebug = true
|
||||
defer func() {
|
||||
os.Remove(home)
|
||||
flagDebug = dbg
|
||||
}()
|
||||
|
||||
var buf bytes.Buffer
|
||||
fake := testclient.Fake{}
|
||||
cmd := &initCmd{
|
||||
out: &buf,
|
||||
home: helmpath.Home(home),
|
||||
kubeClient: fake.Extensions(),
|
||||
clientOnly: true,
|
||||
dryRun: true,
|
||||
}
|
||||
if err := cmd.run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(fake.Actions()) != 0 {
|
||||
t.Error("expected no server calls")
|
||||
}
|
||||
|
||||
var y map[string]interface{}
|
||||
if err := yaml.Unmarshal(buf.Bytes(), &y); err != nil {
|
||||
t.Errorf("Expected parseable YAML, got %q\n\t%s", buf.String(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureHome(t *testing.T) {
|
||||
home, err := ioutil.TempDir("", "helm_home")
|
||||
if err != nil {
|
||||
|
|
|
@ -19,6 +19,8 @@ package installer // import "k8s.io/helm/cmd/helm/installer"
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned"
|
||||
|
@ -36,15 +38,29 @@ const defaultImage = "gcr.io/kubernetes-helm/tiller"
|
|||
//
|
||||
// If verbose is true, this will print the manifest to stdout.
|
||||
func Install(client unversioned.DeploymentsNamespacer, namespace, image string, canary, verbose bool) error {
|
||||
obj := deployment(image, canary)
|
||||
_, err := client.Deployments(namespace).Create(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
// deployment gets the deployment object that installs Tiller.
|
||||
func deployment(image string, canary bool) *extensions.Deployment {
|
||||
switch {
|
||||
case canary:
|
||||
image = defaultImage + ":canary"
|
||||
case image == "":
|
||||
image = fmt.Sprintf("%s:%s", defaultImage, version.Version)
|
||||
}
|
||||
obj := generateDeployment(image)
|
||||
_, err := client.Deployments(namespace).Create(obj)
|
||||
return err
|
||||
return generateDeployment(image)
|
||||
}
|
||||
|
||||
// DeploymentManifest gets the manifest (as a string) that describes the Tiller Deployment
|
||||
// resource.
|
||||
func DeploymentManifest(image string, canary bool) (string, error) {
|
||||
obj := deployment(image, canary)
|
||||
|
||||
buf, err := yaml.Marshal(obj)
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
func generateLabels(labels map[string]string) map[string]string {
|
||||
|
|
|
@ -20,11 +20,45 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/helm/pkg/version"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestDeploymentManifest(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
image string
|
||||
canary bool
|
||||
expect string
|
||||
}{
|
||||
{"default", "", false, "gcr.io/kubernetes-helm/tiller:" + version.Version},
|
||||
{"canary", "example.com/tiller", true, "gcr.io/kubernetes-helm/tiller:canary"},
|
||||
{"custom", "example.com/tiller:latest", false, "example.com/tiller:latest"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
o, err := DeploymentManifest(tt.image, tt.canary)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: error %q", tt.name, err)
|
||||
}
|
||||
var dep extensions.Deployment
|
||||
if err := yaml.Unmarshal([]byte(o), &dep); err != nil {
|
||||
t.Fatalf("%s: error %q", tt.name, err)
|
||||
}
|
||||
|
||||
if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect {
|
||||
t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
|
||||
|
||||
|
|
Loading…
Reference in New Issue