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 }