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  }