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

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/client-go/kubernetes/fake"
    29  	"k8s.io/client-go/pkg/api/v1"
    30  	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
    31  	testcore "k8s.io/client-go/testing"
    32  
    33  	"k8s.io/helm/pkg/version"
    34  )
    35  
    36  func TestDeploymentManifest(t *testing.T) {
    37  	tests := []struct {
    38  		name            string
    39  		image           string
    40  		canary          bool
    41  		expect          string
    42  		imagePullPolicy v1.PullPolicy
    43  	}{
    44  		{"default", "", false, "gcr.io/kubernetes-helm/tiller:" + version.Version, "IfNotPresent"},
    45  		{"canary", "example.com/tiller", true, "gcr.io/kubernetes-helm/tiller:canary", "Always"},
    46  		{"custom", "example.com/tiller:latest", false, "example.com/tiller:latest", "IfNotPresent"},
    47  	}
    48  
    49  	for _, tt := range tests {
    50  		o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary})
    51  		if err != nil {
    52  			t.Fatalf("%s: error %q", tt.name, err)
    53  		}
    54  		var dep v1beta1.Deployment
    55  		if err := yaml.Unmarshal([]byte(o), &dep); err != nil {
    56  			t.Fatalf("%s: error %q", tt.name, err)
    57  		}
    58  
    59  		if got := dep.Spec.Template.Spec.Containers[0].Image; got != tt.expect {
    60  			t.Errorf("%s: expected image %q, got %q", tt.name, tt.expect, got)
    61  		}
    62  
    63  		if got := dep.Spec.Template.Spec.Containers[0].ImagePullPolicy; got != tt.imagePullPolicy {
    64  			t.Errorf("%s: expected imagePullPolicy %q, got %q", tt.name, tt.imagePullPolicy, got)
    65  		}
    66  
    67  		if got := dep.Spec.Template.Spec.Containers[0].Env[0].Value; got != v1.NamespaceDefault {
    68  			t.Errorf("%s: expected namespace %q, got %q", tt.name, v1.NamespaceDefault, got)
    69  		}
    70  	}
    71  }
    72  
    73  func TestDeploymentManifestForServiceAccount(t *testing.T) {
    74  	tests := []struct {
    75  		name            string
    76  		image           string
    77  		canary          bool
    78  		expect          string
    79  		imagePullPolicy v1.PullPolicy
    80  		serviceAccount  string
    81  	}{
    82  		{"withSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", "service-account"},
    83  		{"withoutSA", "", false, "gcr.io/kubernetes-helm/tiller:latest", "IfNotPresent", ""},
    84  	}
    85  	for _, tt := range tests {
    86  		o, err := DeploymentManifest(&Options{Namespace: v1.NamespaceDefault, ImageSpec: tt.image, UseCanary: tt.canary, ServiceAccount: tt.serviceAccount})
    87  		if err != nil {
    88  			t.Fatalf("%s: error %q", tt.name, err)
    89  		}
    90  
    91  		var d v1beta1.Deployment
    92  		if err := yaml.Unmarshal([]byte(o), &d); err != nil {
    93  			t.Fatalf("%s: error %q", tt.name, err)
    94  		}
    95  		if got := d.Spec.Template.Spec.ServiceAccountName; got != tt.serviceAccount {
    96  			t.Errorf("%s: expected service account value %q, got %q", tt.name, tt.serviceAccount, got)
    97  		}
    98  	}
    99  }
   100  
   101  func TestDeploymentManifest_WithTLS(t *testing.T) {
   102  	tests := []struct {
   103  		opts   Options
   104  		name   string
   105  		enable string
   106  		verify string
   107  	}{
   108  		{
   109  			Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: true},
   110  			"tls enable (true), tls verify (true)",
   111  			"1",
   112  			"1",
   113  		},
   114  		{
   115  			Options{Namespace: v1.NamespaceDefault, EnableTLS: true, VerifyTLS: false},
   116  			"tls enable (true), tls verify (false)",
   117  			"1",
   118  			"",
   119  		},
   120  		{
   121  			Options{Namespace: v1.NamespaceDefault, EnableTLS: false, VerifyTLS: true},
   122  			"tls enable (false), tls verify (true)",
   123  			"1",
   124  			"1",
   125  		},
   126  	}
   127  	for _, tt := range tests {
   128  		o, err := DeploymentManifest(&tt.opts)
   129  		if err != nil {
   130  			t.Fatalf("%s: error %q", tt.name, err)
   131  		}
   132  
   133  		var d v1beta1.Deployment
   134  		if err := yaml.Unmarshal([]byte(o), &d); err != nil {
   135  			t.Fatalf("%s: error %q", tt.name, err)
   136  		}
   137  		// verify environment variable in deployment reflect the use of tls being enabled.
   138  		if got := d.Spec.Template.Spec.Containers[0].Env[1].Value; got != tt.verify {
   139  			t.Errorf("%s: expected tls verify env value %q, got %q", tt.name, tt.verify, got)
   140  		}
   141  		if got := d.Spec.Template.Spec.Containers[0].Env[2].Value; got != tt.enable {
   142  			t.Errorf("%s: expected tls enable env value %q, got %q", tt.name, tt.enable, got)
   143  		}
   144  	}
   145  }
   146  
   147  func TestServiceManifest(t *testing.T) {
   148  	o, err := ServiceManifest(v1.NamespaceDefault)
   149  	if err != nil {
   150  		t.Fatalf("error %q", err)
   151  	}
   152  	var svc v1.Service
   153  	if err := yaml.Unmarshal([]byte(o), &svc); err != nil {
   154  		t.Fatalf("error %q", err)
   155  	}
   156  
   157  	if got := svc.ObjectMeta.Namespace; got != v1.NamespaceDefault {
   158  		t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got)
   159  	}
   160  }
   161  
   162  func TestSecretManifest(t *testing.T) {
   163  	o, err := SecretManifest(&Options{
   164  		VerifyTLS:     true,
   165  		EnableTLS:     true,
   166  		Namespace:     v1.NamespaceDefault,
   167  		TLSKeyFile:    tlsTestFile(t, "key.pem"),
   168  		TLSCertFile:   tlsTestFile(t, "crt.pem"),
   169  		TLSCaCertFile: tlsTestFile(t, "ca.pem"),
   170  	})
   171  
   172  	if err != nil {
   173  		t.Fatalf("error %q", err)
   174  	}
   175  
   176  	var obj v1.Secret
   177  	if err := yaml.Unmarshal([]byte(o), &obj); err != nil {
   178  		t.Fatalf("error %q", err)
   179  	}
   180  
   181  	if got := obj.ObjectMeta.Namespace; got != v1.NamespaceDefault {
   182  		t.Errorf("expected namespace %s, got %s", v1.NamespaceDefault, got)
   183  	}
   184  	if _, ok := obj.Data["tls.key"]; !ok {
   185  		t.Errorf("missing 'tls.key' in generated secret object")
   186  	}
   187  	if _, ok := obj.Data["tls.crt"]; !ok {
   188  		t.Errorf("missing 'tls.crt' in generated secret object")
   189  	}
   190  	if _, ok := obj.Data["ca.crt"]; !ok {
   191  		t.Errorf("missing 'ca.crt' in generated secret object")
   192  	}
   193  }
   194  
   195  func TestInstall(t *testing.T) {
   196  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   197  
   198  	fc := &fake.Clientset{}
   199  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   200  		obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment)
   201  		l := obj.GetLabels()
   202  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   203  			t.Errorf("expected labels = '', got '%s'", l)
   204  		}
   205  		i := obj.Spec.Template.Spec.Containers[0].Image
   206  		if i != image {
   207  			t.Errorf("expected image = '%s', got '%s'", image, i)
   208  		}
   209  		return true, obj, nil
   210  	})
   211  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   212  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   213  		l := obj.GetLabels()
   214  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   215  			t.Errorf("expected labels = '', got '%s'", l)
   216  		}
   217  		n := obj.ObjectMeta.Namespace
   218  		if n != v1.NamespaceDefault {
   219  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   220  		}
   221  		return true, obj, nil
   222  	})
   223  
   224  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image}
   225  	if err := Install(fc, opts); err != nil {
   226  		t.Errorf("unexpected error: %#+v", err)
   227  	}
   228  
   229  	if actions := fc.Actions(); len(actions) != 2 {
   230  		t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions))
   231  	}
   232  }
   233  
   234  func TestInstall_WithTLS(t *testing.T) {
   235  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   236  	name := "tiller-secret"
   237  
   238  	fc := &fake.Clientset{}
   239  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   240  		obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment)
   241  		l := obj.GetLabels()
   242  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   243  			t.Errorf("expected labels = '', got '%s'", l)
   244  		}
   245  		i := obj.Spec.Template.Spec.Containers[0].Image
   246  		if i != image {
   247  			t.Errorf("expected image = '%s', got '%s'", image, i)
   248  		}
   249  		return true, obj, nil
   250  	})
   251  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   252  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   253  		l := obj.GetLabels()
   254  		if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   255  			t.Errorf("expected labels = '', got '%s'", l)
   256  		}
   257  		n := obj.ObjectMeta.Namespace
   258  		if n != v1.NamespaceDefault {
   259  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   260  		}
   261  		return true, obj, nil
   262  	})
   263  	fc.AddReactor("create", "secrets", func(action testcore.Action) (bool, runtime.Object, error) {
   264  		obj := action.(testcore.CreateAction).GetObject().(*v1.Secret)
   265  		if l := obj.GetLabels(); reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
   266  			t.Errorf("expected labels = '', got '%s'", l)
   267  		}
   268  		if n := obj.ObjectMeta.Namespace; n != v1.NamespaceDefault {
   269  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   270  		}
   271  		if s := obj.ObjectMeta.Name; s != name {
   272  			t.Errorf("expected name = '%s', got '%s'", name, s)
   273  		}
   274  		if _, ok := obj.Data["tls.key"]; !ok {
   275  			t.Errorf("missing 'tls.key' in generated secret object")
   276  		}
   277  		if _, ok := obj.Data["tls.crt"]; !ok {
   278  			t.Errorf("missing 'tls.crt' in generated secret object")
   279  		}
   280  		if _, ok := obj.Data["ca.crt"]; !ok {
   281  			t.Errorf("missing 'ca.crt' in generated secret object")
   282  		}
   283  		return true, obj, nil
   284  	})
   285  
   286  	opts := &Options{
   287  		Namespace:     v1.NamespaceDefault,
   288  		ImageSpec:     image,
   289  		EnableTLS:     true,
   290  		VerifyTLS:     true,
   291  		TLSKeyFile:    tlsTestFile(t, "key.pem"),
   292  		TLSCertFile:   tlsTestFile(t, "crt.pem"),
   293  		TLSCaCertFile: tlsTestFile(t, "ca.pem"),
   294  	}
   295  
   296  	if err := Install(fc, opts); err != nil {
   297  		t.Errorf("unexpected error: %#+v", err)
   298  	}
   299  
   300  	if actions := fc.Actions(); len(actions) != 3 {
   301  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   302  	}
   303  }
   304  
   305  func TestInstall_canary(t *testing.T) {
   306  	fc := &fake.Clientset{}
   307  	fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   308  		obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment)
   309  		i := obj.Spec.Template.Spec.Containers[0].Image
   310  		if i != "gcr.io/kubernetes-helm/tiller:canary" {
   311  			t.Errorf("expected canary image, got '%s'", i)
   312  		}
   313  		return true, obj, nil
   314  	})
   315  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   316  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   317  		return true, obj, nil
   318  	})
   319  
   320  	opts := &Options{Namespace: v1.NamespaceDefault, UseCanary: true}
   321  	if err := Install(fc, opts); err != nil {
   322  		t.Errorf("unexpected error: %#+v", err)
   323  	}
   324  
   325  	if actions := fc.Actions(); len(actions) != 2 {
   326  		t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions))
   327  	}
   328  }
   329  
   330  func TestUpgrade(t *testing.T) {
   331  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   332  	serviceAccount := "newServiceAccount"
   333  	existingDeployment := deployment(&Options{
   334  		Namespace:      v1.NamespaceDefault,
   335  		ImageSpec:      "imageToReplace",
   336  		ServiceAccount: "serviceAccountToReplace",
   337  		UseCanary:      false,
   338  	})
   339  	existingService := service(v1.NamespaceDefault)
   340  
   341  	fc := &fake.Clientset{}
   342  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   343  		return true, existingDeployment, nil
   344  	})
   345  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   346  		obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment)
   347  		i := obj.Spec.Template.Spec.Containers[0].Image
   348  		if i != image {
   349  			t.Errorf("expected image = '%s', got '%s'", image, i)
   350  		}
   351  		sa := obj.Spec.Template.Spec.ServiceAccountName
   352  		if sa != serviceAccount {
   353  			t.Errorf("expected serviceAccountName = '%s', got '%s'", serviceAccount, sa)
   354  		}
   355  		return true, obj, nil
   356  	})
   357  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   358  		return true, existingService, nil
   359  	})
   360  
   361  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image, ServiceAccount: serviceAccount}
   362  	if err := Upgrade(fc, opts); err != nil {
   363  		t.Errorf("unexpected error: %#+v", err)
   364  	}
   365  
   366  	if actions := fc.Actions(); len(actions) != 3 {
   367  		t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions))
   368  	}
   369  }
   370  
   371  func TestUpgrade_serviceNotFound(t *testing.T) {
   372  	image := "gcr.io/kubernetes-helm/tiller:v2.0.0"
   373  
   374  	existingDeployment := deployment(&Options{
   375  		Namespace: v1.NamespaceDefault,
   376  		ImageSpec: "imageToReplace",
   377  		UseCanary: false,
   378  	})
   379  
   380  	fc := &fake.Clientset{}
   381  	fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   382  		return true, existingDeployment, nil
   383  	})
   384  	fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
   385  		obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment)
   386  		i := obj.Spec.Template.Spec.Containers[0].Image
   387  		if i != image {
   388  			t.Errorf("expected image = '%s', got '%s'", image, i)
   389  		}
   390  		return true, obj, nil
   391  	})
   392  	fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   393  		return true, nil, apierrors.NewNotFound(v1.Resource("services"), "1")
   394  	})
   395  	fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) {
   396  		obj := action.(testcore.CreateAction).GetObject().(*v1.Service)
   397  		n := obj.ObjectMeta.Namespace
   398  		if n != v1.NamespaceDefault {
   399  			t.Errorf("expected namespace = '%s', got '%s'", v1.NamespaceDefault, n)
   400  		}
   401  		return true, obj, nil
   402  	})
   403  
   404  	opts := &Options{Namespace: v1.NamespaceDefault, ImageSpec: image}
   405  	if err := Upgrade(fc, opts); err != nil {
   406  		t.Errorf("unexpected error: %#+v", err)
   407  	}
   408  
   409  	if actions := fc.Actions(); len(actions) != 4 {
   410  		t.Errorf("unexpected actions: %v, expected 4 actions got %d", actions, len(actions))
   411  	}
   412  }
   413  
   414  func tlsTestFile(t *testing.T, path string) string {
   415  	const tlsTestDir = "../../../testdata"
   416  	path = filepath.Join(tlsTestDir, path)
   417  	if _, err := os.Stat(path); os.IsNotExist(err) {
   418  		t.Fatalf("tls test file %s does not exist", path)
   419  	}
   420  	return path
   421  }