github.com/sdbaiguanghe/helm@v2.16.7+incompatible/cmd/helm/installer/install_test.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package installer // import "k8s.io/helm/cmd/helm/installer"
    18  
    19  import (
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/ghodss/yaml"
    26  	appsv1 "k8s.io/api/apps/v1"
    27  	"k8s.io/api/core/v1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/client-go/kubernetes/fake"
    31  	testcore "k8s.io/client-go/testing"
    32  
    33  	"k8s.io/helm/pkg/chartutil"
    34  	"k8s.io/helm/pkg/version"
    35  )
    36  
    37  func TestDeployment(t *testing.T) {
    38  	tests := []struct {
    39  		name            string
    40  		image           string
    41  		canary          bool
    42  		expect          string
    43  		imagePullPolicy v1.PullPolicy
    44  	}{
    45  		{"default", "", false, "gcr.io/kubernetes-helm/tiller:" + version.Version, "IfNotPresent"},
    46  		{"canary", "example.com/tiller", true, "gcr.io/kubernetes-helm/tiller:canary", "Always"},
    47  		{"custom", "example.com/tiller:latest", false, "example.com/tiller:latest", "IfNotPresent"},
    48  	}
    49  
    50  	for _, tt := range tests {
    51  		dep, err := Deployment(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary})
    52  		if err != nil {
    53  			t.Fatalf("%s: error %q", tt.name, err)
    54  		}
    55  
    56  		// Unreleased versions of helm don't have a release image. See issue 3370
    57  		if tt.name == "default" && version.BuildMetadata == "unreleased" {
    58  			tt.expect = "gcr.io/kubernetes-helm/tiller:canary"
    59  		}
    60  		if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect {
    61  			t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got)
    62  		}
    63  
    64  		if got := dep.Spec.Template.Spec.Containers[0].ImagePullPolicy; got != tt.imagePullPolicy {
    65  			t.Errorf("%s: expected imagePullPolicy %q, got %q", tt.name, tt.imagePullPolicy, got)
    66  		}
    67  
    68  		if got := dep.Spec.Template.Spec.Containers[0].Env[0].Value; got != v1.NamespaceDefault {
    69  			t.Errorf("%s: expected namespace %q, got %q", tt.name, v1.NamespaceDefault, got)
    70  		}
    71  	}
    72  }
    73  
    74  func TestDeploymentForServiceAccount(t *testing.T) {
    75  	tests := []struct {
    76  		name            string
    77  		image           string
    78  		canary          bool
    79  		expect          string
    80  		imagePullPolicy v1.PullPolicy
    81  		serviceAccount  string
    82  	}{
    83  		{"withSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", "service-account"},
    84  		{"withoutSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", ""},
    85  	}
    86  	for _, tt := range tests {
    87  		opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount}
    88  		d, err := Deployment(opts)
    89  		if err != nil {
    90  			t.Fatalf("%s: error %q", tt.name, err)
    91  		}
    92  
    93  		if got := d.Spec.Template.Spec.ServiceAccountName; got != tt.serviceAccount {
    94  			t.Errorf("%s: expected service account value %q, got %q", tt.name, tt.serviceAccount, got)
    95  		}
    96  		if got := *d.Spec.Template.Spec.AutomountServiceAccountToken; got != false {
    97  			t.Errorf("%s: expected AutomountServiceAccountToken = %t, got %t", tt.name, false, got)
    98  		}
    99  
   100  		opts.AutoMountServiceAccountToken = true
   101  		d, err = Deployment(opts)
   102  		if err != nil {
   103  			t.Fatalf("%s: error %q", tt.name, err)
   104  		}
   105  		if got := *d.Spec.Template.Spec.AutomountServiceAccountToken; got != true {
   106  			t.Errorf("%s: expected AutomountServiceAccountToken = %t, got %t", tt.name, true, got)
   107  		}
   108  	}
   109  }
   110  
   111  func TestDeployment_WithTLS(t *testing.T) {
   112  	tests := []struct {
   113  		opts   Options
   114  		name   string
   115  		enable string
   116  		verify string
   117  	}{
   118  		{
   119  			Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: true},
   120  			"tls enable (true), tls verify (true)",
   121  			"1",
   122  			"1",
   123  		},
   124  		{
   125  			Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: false},
   126  			"tls enable (true), tls verify (false)",
   127  			"1",
   128  			"",
   129  		},
   130  		{
   131  			Options{Namespace: v1.NamespaceDefault, EnableTLS: false, VerifyTLS: true},
   132  			"tls enable (false), tls verify (true)",
   133  			"1",
   134  			"1",
   135  		},
   136  	}
   137  	for _, tt := range tests {
   138  		d, err := Deployment(&tt.opts)
   139  		if err != nil {
   140  			t.Fatalf("%s: error %q", tt.name, err)
   141  		}
   142  
   143  		// verify environment variable in deployment reflect the use of tls being enabled.
   144  		if got := d.Spec.Template.Spec.Containers[0].Env[2].Value; got != tt.verify {
   145  			t.Errorf("%s: expected tls verify env value %q, got %q", tt.name, tt.verify, got)
   146  		}
   147  		if got := d.Spec.Template.Spec.Containers[0].Env[3].Value; got != tt.enable {
   148  			t.Errorf("%s: expected tls enable env value %q, got %q", tt.name, tt.enable, got)
   149  		}
   150  	}
   151  }
   152  
   153  func TestServiceManifest(t *testing.T) {
   154  	svc := Service(v1.NamespaceDefault)
   155  
   156  	if got := svc.ObjectMeta.Namespace; got != v1.NamespaceDefault {
   157  		t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got)
   158  	}
   159  }
   160  
   161  func TestSecretManifest(t *testing.T) {
   162  	obj, err := Secret(&Options{
   163  		VerifyTLS:     true,
   164  		EnableTLS:     true,
   165  		Namespace:     v1.NamespaceDefault,
   166  		TLSKeyFile:    tlsTestFile(t, "key.pem"),
   167  		TLSCertFile:   tlsTestFile(t, "crt.pem"),
   168  		TLSCaCertFile: tlsTestFile(t, "ca.pem"),
   169  	})
   170  
   171  	if err != nil {
   172  		t.Fatalf("error %q", err)
   173  	}
   174  
   175  	if got := obj.ObjectMeta.Namespace; got != v1.NamespaceDefault {
   176  		t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got)
   177  	}
   178  	if _, ok := obj.Data["tls.key"]; !ok {
   179  		t.Errorf("missing 'tls.key' in generated secret object")
   180  	}
   181  	if _, ok := obj.Data["tls.crt"]; !ok {
   182  		t.Errorf("missing 'tls.crt' in generated secret object")
   183  	}
   184  	if _, ok := obj.Data["ca.crt"]; !ok {
   185  		t.Errorf("missing 'ca.crt' in generated secret object")
   186  	}
   187  }
   188  
   189  func TestInstall(t *testing.T) {
   190  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   191  
   192  	fc := &fake.Clientset{}
   193  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   194  		obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
   195  		l := obj.GetLabels()
   196  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   197  			t.Errorf("expected labels = '', got '%s'", l)
   198  		}
   199  		i := obj.Spec.Template.Spec.Containers[0].Image
   200  		if i != image {
   201  			t.Errorf("expected image = '%s', got '%s'", image, i)
   202  		}
   203  		ports := len(obj.Spec.Template.Spec.Containers[0].Ports)
   204  		if ports != 2 {
   205  			t.Errorf("expected ports = 2, got '%d'", ports)
   206  		}
   207  		replicas := obj.Spec.Replicas
   208  		if int(*replicas) != 1 {
   209  			t.Errorf("expected replicas = 1, got '%d'", replicas)
   210  		}
   211  		return true, obj, nil
   212  	})
   213  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   214  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   215  		l := obj.GetLabels()
   216  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   217  			t.Errorf("expected labels = '', got '%s'", l)
   218  		}
   219  		n := obj.ObjectMeta.Namespace
   220  		if n != v1.NamespaceDefault {
   221  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   222  		}
   223  		return true, obj, nil
   224  	})
   225  
   226  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image}
   227  	if err := Install(fc, opts); err != nil {
   228  		t.Errorf("unexpected error: %#+v", err)
   229  	}
   230  
   231  	if actions := fc.Actions(); len(actions) != 2 {
   232  		t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions))
   233  	}
   234  }
   235  
   236  func TestInstallHA(t *testing.T) {
   237  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   238  
   239  	fc := &fake.Clientset{}
   240  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   241  		obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
   242  		replicas := obj.Spec.Replicas
   243  		if int(*replicas) != 2 {
   244  			t.Errorf("expected replicas = 2, got '%d'", replicas)
   245  		}
   246  		return true, obj, nil
   247  	})
   248  
   249  	opts := &Options{
   250  		Namespace: v1.NamespaceDefault,
   251  		ImageSpec: image,
   252  		Replicas:  2,
   253  	}
   254  	if err := Install(fc, opts); err != nil {
   255  		t.Errorf("unexpected error: %#+v", err)
   256  	}
   257  }
   258  
   259  func TestInstall_WithTLS(t *testing.T) {
   260  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   261  	name := "tiller-secret"
   262  
   263  	fc := &fake.Clientset{}
   264  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   265  		obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
   266  		l := obj.GetLabels()
   267  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   268  			t.Errorf("expected labels = '', got '%s'", l)
   269  		}
   270  		i := obj.Spec.Template.Spec.Containers[0].Image
   271  		if i != image {
   272  			t.Errorf("expected image = '%s', got '%s'", image, i)
   273  		}
   274  		return true, obj, nil
   275  	})
   276  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   277  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   278  		l := obj.GetLabels()
   279  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   280  			t.Errorf("expected labels = '', got '%s'", l)
   281  		}
   282  		n := obj.ObjectMeta.Namespace
   283  		if n != v1.NamespaceDefault {
   284  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   285  		}
   286  		return true, obj, nil
   287  	})
   288  	fc.AddReactor("create", "secrets", func(action testcore.Action) (bool, runtime.Object, error) {
   289  		obj := action.(testcore.CreateAction).GetObject().(*v1.Secret)
   290  		if l := obj.GetLabels(); reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   291  			t.Errorf("expected labels = '', got '%s'", l)
   292  		}
   293  		if n := obj.ObjectMeta.Namespace; n != v1.NamespaceDefault {
   294  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   295  		}
   296  		if s := obj.ObjectMeta.Name; s != name {
   297  			t.Errorf("expected name = '%s', got '%s'", name, s)
   298  		}
   299  		if _, ok := obj.Data["tls.key"]; !ok {
   300  			t.Errorf("missing 'tls.key' in generated secret object")
   301  		}
   302  		if _, ok := obj.Data["tls.crt"]; !ok {
   303  			t.Errorf("missing 'tls.crt' in generated secret object")
   304  		}
   305  		if _, ok := obj.Data["ca.crt"]; !ok {
   306  			t.Errorf("missing 'ca.crt' in generated secret object")
   307  		}
   308  		return true, obj, nil
   309  	})
   310  
   311  	opts := &Options{
   312  		Namespace:     v1.NamespaceDefault,
   313  		ImageSpec:     image,
   314  		EnableTLS:     true,
   315  		VerifyTLS:     true,
   316  		TLSKeyFile:    tlsTestFile(t, "key.pem"),
   317  		TLSCertFile:   tlsTestFile(t, "crt.pem"),
   318  		TLSCaCertFile: tlsTestFile(t, "ca.pem"),
   319  	}
   320  
   321  	if err := Install(fc, opts); err != nil {
   322  		t.Errorf("unexpected error: %#+v", err)
   323  	}
   324  
   325  	if actions := fc.Actions(); len(actions) != 3 {
   326  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   327  	}
   328  }
   329  
   330  func TestInstall_canary(t *testing.T) {
   331  	fc := &fake.Clientset{}
   332  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   333  		obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
   334  		i := obj.Spec.Template.Spec.Containers[0].Image
   335  		if i != "gcr.io/kubernetes-helm/tiller:canary" {
   336  			t.Errorf("expected canary image, got '%s'", i)
   337  		}
   338  		return true, obj, nil
   339  	})
   340  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   341  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   342  		return true, obj, nil
   343  	})
   344  
   345  	opts := &Options{Namespace: v1.NamespaceDefault, UseCanary: true}
   346  	if err := Install(fc, opts); err != nil {
   347  		t.Errorf("unexpected error: %#+v", err)
   348  	}
   349  
   350  	if actions := fc.Actions(); len(actions) != 2 {
   351  		t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions))
   352  	}
   353  }
   354  
   355  func TestUpgrade(t *testing.T) {
   356  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   357  	serviceAccount := "newServiceAccount"
   358  	existingDeployment, _ := generateDeployment(&Options{
   359  		Namespace:      v1.NamespaceDefault,
   360  		ImageSpec:      "imageToReplace:v1.0.0",
   361  		ServiceAccount: "serviceAccountToReplace",
   362  		UseCanary:      false,
   363  	})
   364  	existingService := generateService(v1.NamespaceDefault)
   365  
   366  	fc := &fake.Clientset{}
   367  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   368  		return true, existingDeployment, nil
   369  	})
   370  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   371  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   372  		i := obj.Spec.Template.Spec.Containers[0].Image
   373  		if i != image {
   374  			t.Errorf("expected image = '%s', got '%s'", image, i)
   375  		}
   376  		sa := obj.Spec.Template.Spec.ServiceAccountName
   377  		if sa != serviceAccount {
   378  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   379  		}
   380  		return true, obj, nil
   381  	})
   382  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   383  		return true, existingService, nil
   384  	})
   385  
   386  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount}
   387  	if err := Upgrade(fc, opts); err != nil {
   388  		t.Errorf("unexpected error: %#+v", err)
   389  	}
   390  
   391  	if actions := fc.Actions(); len(actions) != 3 {
   392  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   393  	}
   394  }
   395  
   396  func TestUpgrade_serviceNotFound(t *testing.T) {
   397  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   398  
   399  	existingDeployment, _ := generateDeployment(&Options{
   400  		Namespace: v1.NamespaceDefault,
   401  		ImageSpec: "imageToReplace",
   402  		UseCanary: false,
   403  	})
   404  
   405  	fc := &fake.Clientset{}
   406  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   407  		return true, existingDeployment, nil
   408  	})
   409  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   410  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   411  		i := obj.Spec.Template.Spec.Containers[0].Image
   412  		if i != image {
   413  			t.Errorf("expected image = '%s', got '%s'", image, i)
   414  		}
   415  		return true, obj, nil
   416  	})
   417  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   418  		return true, nil, apierrors.NewNotFound(v1.Resource("services"), "1")
   419  	})
   420  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   421  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   422  		n := obj.ObjectMeta.Namespace
   423  		if n != v1.NamespaceDefault {
   424  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   425  		}
   426  		return true, obj, nil
   427  	})
   428  
   429  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image}
   430  	if err := Upgrade(fc, opts); err != nil {
   431  		t.Errorf("unexpected error: %#+v", err)
   432  	}
   433  
   434  	if actions := fc.Actions(); len(actions) != 4 {
   435  		t.Errorf("unexpected actions: %v, expected 4 actions got %d", actions, len(actions))
   436  	}
   437  }
   438  
   439  func TestUgrade_newerVersion(t *testing.T) {
   440  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   441  	serviceAccount := "newServiceAccount"
   442  	existingDeployment, _ := generateDeployment(&Options{
   443  		Namespace:      v1.NamespaceDefault,
   444  		ImageSpec:      "imageToReplace:v100.5.0",
   445  		ServiceAccount: "serviceAccountToReplace",
   446  		UseCanary:      false,
   447  	})
   448  	existingService := generateService(v1.NamespaceDefault)
   449  
   450  	fc := &fake.Clientset{}
   451  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   452  		return true, existingDeployment, nil
   453  	})
   454  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   455  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   456  		i := obj.Spec.Template.Spec.Containers[0].Image
   457  		if i != image {
   458  			t.Errorf("expected image = '%s', got '%s'", image, i)
   459  		}
   460  		sa := obj.Spec.Template.Spec.ServiceAccountName
   461  		if sa != serviceAccount {
   462  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   463  		}
   464  		return true, obj, nil
   465  	})
   466  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   467  		return true, existingService, nil
   468  	})
   469  
   470  	opts := &Options{
   471  		Namespace:      v1.NamespaceDefault,
   472  		ImageSpec:      image,
   473  		ServiceAccount: serviceAccount,
   474  		ForceUpgrade:   false,
   475  	}
   476  	if err := Upgrade(fc, opts); err == nil {
   477  		t.Errorf("Expected error because the deployed version is newer")
   478  	}
   479  
   480  	if actions := fc.Actions(); len(actions) != 1 {
   481  		t.Errorf("unexpected actions: %v, expected 1 action got %d", actions, len(actions))
   482  	}
   483  
   484  	opts = &Options{
   485  		Namespace:      v1.NamespaceDefault,
   486  		ImageSpec:      image,
   487  		ServiceAccount: serviceAccount,
   488  		ForceUpgrade:   true,
   489  	}
   490  	if err := Upgrade(fc, opts); err != nil {
   491  		t.Errorf("unexpected error: %#+v", err)
   492  	}
   493  
   494  	if actions := fc.Actions(); len(actions) != 4 {
   495  		t.Errorf("unexpected actions: %v, expected 4 action got %d", actions, len(actions))
   496  	}
   497  }
   498  
   499  func TestUpgrade_identical(t *testing.T) {
   500  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   501  	serviceAccount := "newServiceAccount"
   502  	existingDeployment, _ := generateDeployment(&Options{
   503  		Namespace:      v1.NamespaceDefault,
   504  		ImageSpec:      "imageToReplace:v2.0.0",
   505  		ServiceAccount: "serviceAccountToReplace",
   506  		UseCanary:      false,
   507  	})
   508  	existingService := generateService(v1.NamespaceDefault)
   509  
   510  	fc := &fake.Clientset{}
   511  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   512  		return true, existingDeployment, nil
   513  	})
   514  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   515  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   516  		i := obj.Spec.Template.Spec.Containers[0].Image
   517  		if i != image {
   518  			t.Errorf("expected image = '%s', got '%s'", image, i)
   519  		}
   520  		sa := obj.Spec.Template.Spec.ServiceAccountName
   521  		if sa != serviceAccount {
   522  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   523  		}
   524  		return true, obj, nil
   525  	})
   526  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   527  		return true, existingService, nil
   528  	})
   529  
   530  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount}
   531  	if err := Upgrade(fc, opts); err != nil {
   532  		t.Errorf("unexpected error: %#+v", err)
   533  	}
   534  
   535  	if actions := fc.Actions(); len(actions) != 3 {
   536  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   537  	}
   538  }
   539  
   540  func TestUpgrade_canaryClient(t *testing.T) {
   541  	image := "gcr.io/kubernetes-helm/tiller:canary"
   542  	serviceAccount := "newServiceAccount"
   543  	existingDeployment, _ := generateDeployment(&Options{
   544  		Namespace:      v1.NamespaceDefault,
   545  		ImageSpec:      "imageToReplace:v1.0.0",
   546  		ServiceAccount: "serviceAccountToReplace",
   547  		UseCanary:      false,
   548  	})
   549  	existingService := generateService(v1.NamespaceDefault)
   550  
   551  	fc := &fake.Clientset{}
   552  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   553  		return true, existingDeployment, nil
   554  	})
   555  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   556  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   557  		i := obj.Spec.Template.Spec.Containers[0].Image
   558  		if i != image {
   559  			t.Errorf("expected image = '%s', got '%s'", image, i)
   560  		}
   561  		sa := obj.Spec.Template.Spec.ServiceAccountName
   562  		if sa != serviceAccount {
   563  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   564  		}
   565  		return true, obj, nil
   566  	})
   567  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   568  		return true, existingService, nil
   569  	})
   570  
   571  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount}
   572  	if err := Upgrade(fc, opts); err != nil {
   573  		t.Errorf("unexpected error: %#+v", err)
   574  	}
   575  
   576  	if actions := fc.Actions(); len(actions) != 3 {
   577  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   578  	}
   579  }
   580  
   581  func TestUpgrade_canaryServer(t *testing.T) {
   582  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   583  	serviceAccount := "newServiceAccount"
   584  	existingDeployment, _ := generateDeployment(&Options{
   585  		Namespace:      v1.NamespaceDefault,
   586  		ImageSpec:      "imageToReplace:canary",
   587  		ServiceAccount: "serviceAccountToReplace",
   588  		UseCanary:      false,
   589  	})
   590  	existingService := generateService(v1.NamespaceDefault)
   591  
   592  	fc := &fake.Clientset{}
   593  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   594  		return true, existingDeployment, nil
   595  	})
   596  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   597  		obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
   598  		i := obj.Spec.Template.Spec.Containers[0].Image
   599  		if i != image {
   600  			t.Errorf("expected image = '%s', got '%s'", image, i)
   601  		}
   602  		sa := obj.Spec.Template.Spec.ServiceAccountName
   603  		if sa != serviceAccount {
   604  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   605  		}
   606  		return true, obj, nil
   607  	})
   608  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   609  		return true, existingService, nil
   610  	})
   611  
   612  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount}
   613  	if err := Upgrade(fc, opts); err != nil {
   614  		t.Errorf("unexpected error: %#+v", err)
   615  	}
   616  
   617  	if actions := fc.Actions(); len(actions) != 3 {
   618  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   619  	}
   620  }
   621  
   622  func tlsTestFile(t *testing.T, path string) string {
   623  	const tlsTestDir = "../../../testdata"
   624  	path = filepath.Join(tlsTestDir, path)
   625  	if _, err := os.Stat(path); os.IsNotExist(err) {
   626  		t.Fatalf("tls test file %s does not exist", path)
   627  	}
   628  	return path
   629  }
   630  
   631  func TestDeployment_WithNodeSelectors(t *testing.T) {
   632  	tests := []struct {
   633  		opts   Options
   634  		name   string
   635  		expect map[string]interface{}
   636  	}{
   637  		{
   638  			Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller"},
   639  			"nodeSelector app=tiller",
   640  			map[string]interface{}{"app": "tiller"},
   641  		},
   642  		{
   643  			Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,helm=rocks"},
   644  			"nodeSelector app=tiller, helm=rocks",
   645  			map[string]interface{}{"app": "tiller", "helm": "rocks"},
   646  		},
   647  		// note: nodeSelector key and value are strings
   648  		{
   649  			Options{Namespace: v1.NamespaceDefault, NodeSelectors: "app=tiller,minCoolness=1"},
   650  			"nodeSelector app=tiller, helm=rocks",
   651  			map[string]interface{}{"app": "tiller", "minCoolness": "1"},
   652  		},
   653  	}
   654  	for _, tt := range tests {
   655  		d, err := Deployment(&tt.opts)
   656  		if err != nil {
   657  			t.Fatalf("%s: error %q", tt.name, err)
   658  		}
   659  
   660  		// Verify that environment variables in Deployment reflect the use of TLS being enabled.
   661  		got := d.Spec.Template.Spec.NodeSelector
   662  		for k, v := range tt.expect {
   663  			if got[k] != v {
   664  				t.Errorf("%s: expected nodeSelector value %q, got %q", tt.name, tt.expect, got)
   665  			}
   666  		}
   667  	}
   668  }
   669  
   670  func TestDeployment_WithSetValues(t *testing.T) {
   671  	tests := []struct {
   672  		opts       Options
   673  		name       string
   674  		expectPath string
   675  		expect     interface{}
   676  	}{
   677  		{
   678  			Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.nodeselector.app=tiller"}},
   679  			"setValues spec.template.spec.nodeSelector.app=tiller",
   680  			"spec.template.spec.nodeSelector.app",
   681  			"tiller",
   682  		},
   683  		{
   684  			Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.replicas=2"}},
   685  			"setValues spec.replicas=2",
   686  			"spec.replicas",
   687  			2,
   688  		},
   689  		{
   690  			Options{Namespace: v1.NamespaceDefault, Values: []string{"spec.template.spec.activedeadlineseconds=120"}},
   691  			"setValues spec.template.spec.activedeadlineseconds=120",
   692  			"spec.template.spec.activeDeadlineSeconds",
   693  			120,
   694  		},
   695  	}
   696  	for _, tt := range tests {
   697  		d, err := Deployment(&tt.opts)
   698  		if err != nil {
   699  			t.Fatalf("%s: error %q", tt.name, err)
   700  		}
   701  
   702  		o, err := yaml.Marshal(d)
   703  		if err != nil {
   704  			t.Errorf("Error marshaling Deployment: %s", err)
   705  		}
   706  
   707  		values, err := chartutil.ReadValues(o)
   708  		if err != nil {
   709  			t.Errorf("Error converting Deployment manifest to Values: %s", err)
   710  		}
   711  		// path value
   712  		pv, err := values.PathValue(tt.expectPath)
   713  		if err != nil {
   714  			t.Errorf("Error retrieving path value from Deployment Values: %s", err)
   715  		}
   716  
   717  		// convert our expected value to match the result type for comparison
   718  		ev := tt.expect
   719  		switch pvt := pv.(type) {
   720  		case float64:
   721  			floatType := reflect.TypeOf(float64(0))
   722  			v := reflect.ValueOf(ev)
   723  			v = reflect.Indirect(v)
   724  			if !v.Type().ConvertibleTo(floatType) {
   725  				t.Fatalf("Error converting expected value %v to float64", v.Type())
   726  			}
   727  			fv := v.Convert(floatType)
   728  			if fv.Float() != pvt {
   729  				t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv)
   730  			}
   731  		default:
   732  			if pv != tt.expect {
   733  				t.Errorf("%s: expected value %q, got %q", tt.name, tt.expect, pv)
   734  			}
   735  		}
   736  	}
   737  }