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