github.com/marksheahan/packer@v0.10.2-0.20160613200515-1acb2d6645a0/builder/azure/arm/config_test.go (about) 1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT License. See the LICENSE file in builder/azure for license information. 3 4 package arm 5 6 import ( 7 "fmt" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/mitchellh/packer/builder/azure/common/constants" 13 "github.com/mitchellh/packer/packer" 14 ) 15 16 // List of configuration parameters that are required by the ARM builder. 17 var requiredConfigValues = []string{ 18 "capture_name_prefix", 19 "capture_container_name", 20 "client_id", 21 "client_secret", 22 "image_offer", 23 "image_publisher", 24 "image_sku", 25 "location", 26 "os_type", 27 "storage_account", 28 "resource_group_name", 29 "subscription_id", 30 "tenant_id", 31 } 32 33 func TestConfigShouldProvideReasonableDefaultValues(t *testing.T) { 34 c, _, err := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 35 36 if err != nil { 37 t.Errorf("Expected configuration creation to succeed, but it failed!\n") 38 t.Fatalf(" errors: %s\n", err) 39 } 40 41 if c.UserName == "" { 42 t.Errorf("Expected 'UserName' to be populated, but it was empty!") 43 } 44 45 if c.VMSize == "" { 46 t.Errorf("Expected 'VMSize' to be populated, but it was empty!") 47 } 48 49 if c.ObjectID != "" { 50 t.Errorf("Expected 'ObjectID' to be nil, but it was '%s'!", c.ObjectID) 51 } 52 } 53 54 func TestConfigShouldBeAbleToOverrideDefaultedValues(t *testing.T) { 55 builderValues := getArmBuilderConfiguration() 56 builderValues["ssh_password"] = "override_password" 57 builderValues["ssh_username"] = "override_username" 58 builderValues["vm_size"] = "override_vm_size" 59 builderValues["communicator"] = "ssh" 60 61 c, _, err := newConfig(builderValues, getPackerConfiguration()) 62 63 if err != nil { 64 t.Fatalf("newConfig failed: %s", err) 65 } 66 67 if c.Password != "override_password" { 68 t.Errorf("Expected 'Password' to be set to 'override_password', but found '%s'!", c.Password) 69 } 70 71 if c.Comm.SSHPassword != "override_password" { 72 t.Errorf("Expected 'c.Comm.SSHPassword' to be set to 'override_password', but found '%s'!", c.Comm.SSHPassword) 73 } 74 75 if c.UserName != "override_username" { 76 t.Errorf("Expected 'UserName' to be set to 'override_username', but found '%s'!", c.UserName) 77 } 78 79 if c.Comm.SSHUsername != "override_username" { 80 t.Errorf("Expected 'c.Comm.SSHUsername' to be set to 'override_username', but found '%s'!", c.Comm.SSHUsername) 81 } 82 83 if c.VMSize != "override_vm_size" { 84 t.Errorf("Expected 'vm_size' to be set to 'override_vm_size', but found '%s'!", c.VMSize) 85 } 86 } 87 88 func TestConfigShouldDefaultVMSizeToStandardA1(t *testing.T) { 89 c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 90 91 if c.VMSize != "Standard_A1" { 92 t.Errorf("Expected 'VMSize' to default to 'Standard_A1', but got '%s'.", c.VMSize) 93 } 94 } 95 96 func TestConfigShouldDefaultImageVersionToLatest(t *testing.T) { 97 c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 98 99 if c.ImageVersion != "latest" { 100 t.Errorf("Expected 'ImageVersion' to default to 'latest', but got '%s'.", c.ImageVersion) 101 } 102 } 103 104 func TestConfigShouldNotDefaultImageVersionIfCustomImage(t *testing.T) { 105 config := map[string]string{ 106 "capture_name_prefix": "ignore", 107 "capture_container_name": "ignore", 108 "location": "ignore", 109 "image_url": "ignore", 110 "storage_account": "ignore", 111 "resource_group_name": "ignore", 112 "subscription_id": "ignore", 113 "os_type": constants.Target_Linux, 114 "communicator": "none", 115 } 116 117 c, _, _ := newConfig(config, getPackerConfiguration()) 118 if c.ImageVersion != "" { 119 t.Errorf("Expected 'ImageVersion' to empty, but got '%s'.", c.ImageVersion) 120 } 121 } 122 123 func TestConfigShouldRejectCustomImageAndMarketPlace(t *testing.T) { 124 config := map[string]string{ 125 "capture_name_prefix": "ignore", 126 "capture_container_name": "ignore", 127 "location": "ignore", 128 "image_url": "ignore", 129 "resource_group_name": "ignore", 130 "storage_account": "ignore", 131 "subscription_id": "ignore", 132 "os_type": constants.Target_Linux, 133 "communicator": "none", 134 } 135 packerConfiguration := getPackerConfiguration() 136 marketPlace := []string{"image_publisher", "image_offer", "image_sku"} 137 138 for _, x := range marketPlace { 139 config[x] = "ignore" 140 _, _, err := newConfig(config, packerConfiguration) 141 if err == nil { 142 t.Errorf("Expected Config to reject image_url and %s, but it did not", x) 143 } 144 } 145 } 146 147 func TestConfigShouldDefaultToPublicCloud(t *testing.T) { 148 c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 149 150 if c.CloudEnvironmentName != "Public" { 151 t.Errorf("Expected 'CloudEnvironmentName' to default to 'Public', but got '%s'.", c.CloudEnvironmentName) 152 } 153 154 if c.cloudEnvironment == nil || c.cloudEnvironment.Name != "AzurePublicCloud" { 155 t.Errorf("Expected 'cloudEnvironment' to be set to 'AzurePublicCloud', but got '%s'.", c.cloudEnvironment) 156 } 157 } 158 159 func TestConfigInstantiatesCorrectAzureEnvironment(t *testing.T) { 160 config := map[string]string{ 161 "capture_name_prefix": "ignore", 162 "capture_container_name": "ignore", 163 "image_offer": "ignore", 164 "image_publisher": "ignore", 165 "image_sku": "ignore", 166 "location": "ignore", 167 "storage_account": "ignore", 168 "resource_group_name": "ignore", 169 "subscription_id": "ignore", 170 "os_type": constants.Target_Linux, 171 "communicator": "none", 172 } 173 174 // user input is fun :) 175 var table = []struct { 176 name string 177 environmentName string 178 }{ 179 {"China", "AzureChinaCloud"}, 180 {"ChinaCloud", "AzureChinaCloud"}, 181 {"AzureChinaCloud", "AzureChinaCloud"}, 182 {"aZuReChInAcLoUd", "AzureChinaCloud"}, 183 184 {"USGovernment", "AzureUSGovernmentCloud"}, 185 {"USGovernmentCloud", "AzureUSGovernmentCloud"}, 186 {"AzureUSGovernmentCloud", "AzureUSGovernmentCloud"}, 187 {"aZuReUsGoVeRnMeNtClOuD", "AzureUSGovernmentCloud"}, 188 189 {"Public", "AzurePublicCloud"}, 190 {"PublicCloud", "AzurePublicCloud"}, 191 {"AzurePublicCloud", "AzurePublicCloud"}, 192 {"aZuRePuBlIcClOuD", "AzurePublicCloud"}, 193 } 194 195 packerConfiguration := getPackerConfiguration() 196 197 for _, x := range table { 198 config["cloud_environment_name"] = x.name 199 c, _, err := newConfig(config, packerConfiguration) 200 if err != nil { 201 t.Fatal(err) 202 } 203 204 if c.cloudEnvironment == nil || c.cloudEnvironment.Name != x.environmentName { 205 t.Errorf("Expected 'cloudEnvironment' to be set to '%s', but got '%s'.", x.environmentName, c.cloudEnvironment) 206 } 207 } 208 } 209 210 func TestUserShouldProvideRequiredValues(t *testing.T) { 211 builderValues := getArmBuilderConfiguration() 212 213 // Ensure we can successfully create a config. 214 _, _, err := newConfig(builderValues, getPackerConfiguration()) 215 if err != nil { 216 t.Errorf("Expected configuration creation to succeed, but it failed!\n") 217 t.Fatalf(" -> %+v\n", builderValues) 218 } 219 220 // Take away a required element, and ensure construction fails. 221 for _, v := range requiredConfigValues { 222 originalValue := builderValues[v] 223 delete(builderValues, v) 224 225 _, _, err := newConfig(builderValues, getPackerConfiguration()) 226 if err == nil { 227 t.Errorf("Expected configuration creation to fail, but it succeeded!\n") 228 t.Fatalf(" -> %+v\n", builderValues) 229 } 230 231 builderValues[v] = originalValue 232 } 233 } 234 235 func TestSystemShouldDefineRuntimeValues(t *testing.T) { 236 c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 237 238 if c.Password == "" { 239 t.Errorf("Expected Password to not be empty, but it was '%s'!", c.Password) 240 } 241 242 if c.tmpComputeName == "" { 243 t.Errorf("Expected tmpComputeName to not be empty, but it was '%s'!", c.tmpComputeName) 244 } 245 246 if c.tmpDeploymentName == "" { 247 t.Errorf("Expected tmpDeploymentName to not be empty, but it was '%s'!", c.tmpDeploymentName) 248 } 249 250 if c.tmpResourceGroupName == "" { 251 t.Errorf("Expected tmpResourceGroupName to not be empty, but it was '%s'!", c.tmpResourceGroupName) 252 } 253 254 if c.tmpOSDiskName == "" { 255 t.Errorf("Expected tmpOSDiskName to not be empty, but it was '%s'!", c.tmpOSDiskName) 256 } 257 } 258 259 func TestConfigShouldTransformToVirtualMachineCaptureParameters(t *testing.T) { 260 c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) 261 parameters := c.toVirtualMachineCaptureParameters() 262 263 if *parameters.DestinationContainerName != c.CaptureContainerName { 264 t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.DestinationContainerName, c.CaptureContainerName) 265 } 266 267 if *parameters.VhdPrefix != c.CaptureNamePrefix { 268 t.Errorf("Expected DestinationContainerName to be equal to config's CaptureContainerName, but they were '%s' and '%s' respectively.", *parameters.VhdPrefix, c.CaptureNamePrefix) 269 } 270 271 if *parameters.OverwriteVhds != false { 272 t.Error("Expected OverwriteVhds to be false, but it was not.") 273 } 274 } 275 276 func TestConfigShouldSupportPackersConfigElements(t *testing.T) { 277 c, _, err := newConfig( 278 getArmBuilderConfiguration(), 279 getPackerConfiguration(), 280 getPackerCommunicatorConfiguration()) 281 282 if err != nil { 283 t.Fatal(err) 284 } 285 286 if c.Comm.SSHTimeout != 1*time.Hour { 287 t.Errorf("Expected Comm.SSHTimeout to be a duration of an hour, but got '%s' instead.", c.Comm.SSHTimeout) 288 } 289 290 if c.Comm.WinRMTimeout != 2*time.Hour { 291 t.Errorf("Expected Comm.WinRMTimeout to be a durationof two hours, but got '%s' instead.", c.Comm.WinRMTimeout) 292 } 293 } 294 295 func TestWinRMConfigShouldSetRoundTripDecorator(t *testing.T) { 296 config := getArmBuilderConfiguration() 297 config["communicator"] = "winrm" 298 config["winrm_username"] = "username" 299 config["winrm_password"] = "password" 300 301 c, _, err := newConfig(config, getPackerConfiguration()) 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 if c.Comm.WinRMTransportDecorator == nil { 307 t.Errorf("Expected WinRMTransportDecorator to be set, but it was nil") 308 } 309 } 310 311 func TestUserDeviceLoginIsEnabledForLinux(t *testing.T) { 312 config := map[string]string{ 313 "capture_name_prefix": "ignore", 314 "capture_container_name": "ignore", 315 "image_offer": "ignore", 316 "image_publisher": "ignore", 317 "image_sku": "ignore", 318 "location": "ignore", 319 "storage_account": "ignore", 320 "resource_group_name": "ignore", 321 "subscription_id": "ignore", 322 "os_type": constants.Target_Linux, 323 "communicator": "none", 324 } 325 326 _, _, err := newConfig(config, getPackerConfiguration()) 327 if err != nil { 328 t.Fatalf("failed to use device login for Linux: %s", err) 329 } 330 } 331 332 func TestUseDeviceLoginIsDisabledForWindows(t *testing.T) { 333 config := map[string]string{ 334 "capture_name_prefix": "ignore", 335 "capture_container_name": "ignore", 336 "image_offer": "ignore", 337 "image_publisher": "ignore", 338 "image_sku": "ignore", 339 "location": "ignore", 340 "storage_account": "ignore", 341 "resource_group_name": "ignore", 342 "subscription_id": "ignore", 343 "os_type": constants.Target_Windows, 344 "communicator": "none", 345 } 346 347 _, _, err := newConfig(config, getPackerConfiguration()) 348 if err == nil { 349 t.Fatalf("Expected test to fail, but it succeeded") 350 } 351 352 multiError, _ := err.(*packer.MultiError) 353 if len(multiError.Errors) != 3 { 354 t.Errorf("Expected to find 3 errors, but found %d errors", len(multiError.Errors)) 355 } 356 357 if !strings.Contains(err.Error(), "client_id must be specified") { 358 t.Errorf("Expected to find error for 'client_id must be specified") 359 } 360 if !strings.Contains(err.Error(), "client_secret must be specified") { 361 t.Errorf("Expected to find error for 'client_secret must be specified") 362 } 363 if !strings.Contains(err.Error(), "tenant_id must be specified") { 364 t.Errorf("Expected to find error for 'tenant_id must be specified") 365 } 366 } 367 368 func TestConfigShouldRejectMalformedCaptureNamePrefix(t *testing.T) { 369 config := map[string]string{ 370 "capture_container_name": "ignore", 371 "image_offer": "ignore", 372 "image_publisher": "ignore", 373 "image_sku": "ignore", 374 "location": "ignore", 375 "storage_account": "ignore", 376 "resource_group_name": "ignore", 377 "subscription_id": "ignore", 378 // Does not matter for this test case, just pick one. 379 "os_type": constants.Target_Linux, 380 } 381 382 wellFormedCaptureNamePrefix := []string{ 383 "packer", 384 "AbcdefghijklmnopqrstuvwX", 385 "hypen-hypen", 386 "0leading-number", 387 "v1.core.local", 388 } 389 390 for _, x := range wellFormedCaptureNamePrefix { 391 config["capture_name_prefix"] = x 392 _, _, err := newConfig(config, getPackerConfiguration()) 393 394 if err != nil { 395 t.Errorf("Expected test to pass, but it failed with the well-formed capture_name_prefix set to %q.", x) 396 } 397 } 398 399 malformedCaptureNamePrefix := []string{ 400 "-leading-hypen", 401 "trailing-hypen-", 402 "trailing-period.", 403 "_leading-underscore", 404 "punc-!@#$%^&*()_+-=-punc", 405 "There-are-too-many-characters-in-the-name-and-the-limit-is-twenty-four", 406 } 407 408 for _, x := range malformedCaptureNamePrefix { 409 config["capture_name_prefix"] = x 410 _, _, err := newConfig(config, getPackerConfiguration()) 411 412 if err == nil { 413 t.Errorf("Expected test to fail, but it succeeded with the malformed capture_name_prefix set to %q.", x) 414 } 415 } 416 } 417 418 func TestConfigShouldRejectMalformedCaptureContainerName(t *testing.T) { 419 config := map[string]string{ 420 "capture_name_prefix": "ignore", 421 "image_offer": "ignore", 422 "image_publisher": "ignore", 423 "image_sku": "ignore", 424 "location": "ignore", 425 "storage_account": "ignore", 426 "resource_group_name": "ignore", 427 "subscription_id": "ignore", 428 // Does not matter for this test case, just pick one. 429 "os_type": constants.Target_Linux, 430 } 431 432 wellFormedCaptureContainerName := []string{ 433 "0leading", 434 "aleading", 435 "hype-hypen", 436 "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz", // 63 characters 437 } 438 439 for _, x := range wellFormedCaptureContainerName { 440 config["capture_container_name"] = x 441 _, _, err := newConfig(config, getPackerConfiguration()) 442 443 if err != nil { 444 t.Errorf("Expected test to pass, but it failed with the well-formed capture_container_name set to %q.", x) 445 } 446 } 447 448 malformedCaptureContainerName := []string{ 449 "No-Capitals", 450 "double--hypens", 451 "-leading-hypen", 452 "trailing-hypen-", 453 "punc-!@#$%^&*()_+-=-punc", 454 "there-are-over-63-characters-in-this-string-and-that-is-a-bad-container-name", 455 } 456 457 for _, x := range malformedCaptureContainerName { 458 config["capture_container_name"] = x 459 _, _, err := newConfig(config, getPackerConfiguration()) 460 461 if err == nil { 462 t.Errorf("Expected test to fail, but it succeeded with the malformed capture_container_name set to %q.", x) 463 } 464 } 465 } 466 467 func getArmBuilderConfiguration() map[string]string { 468 m := make(map[string]string) 469 for _, v := range requiredConfigValues { 470 m[v] = fmt.Sprintf("ignored00") 471 } 472 473 m["communicator"] = "none" 474 m["os_type"] = constants.Target_Linux 475 return m 476 } 477 478 func getArmBuilderConfigurationWithWindows() map[string]string { 479 m := make(map[string]string) 480 for _, v := range requiredConfigValues { 481 m[v] = fmt.Sprintf("ignored00") 482 } 483 484 m["object_id"] = "ignored00" 485 m["tenant_id"] = "ignored00" 486 m["winrm_username"] = "ignored00" 487 m["communicator"] = "winrm" 488 m["os_type"] = constants.Target_Windows 489 return m 490 } 491 492 func getPackerConfiguration() interface{} { 493 config := map[string]interface{}{ 494 "packer_build_name": "azure-arm-vm", 495 "packer_builder_type": "azure-arm-vm", 496 "packer_debug": "false", 497 "packer_force": "false", 498 "packer_template_path": "/home/jenkins/azure-arm-vm/template.json", 499 } 500 501 return config 502 } 503 504 func getPackerCommunicatorConfiguration() map[string]string { 505 config := map[string]string{ 506 "ssh_timeout": "1h", 507 "winrm_timeout": "2h", 508 } 509 510 return config 511 }