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  }