github.phpd.cn/hashicorp/packer@v1.3.2/builder/googlecompute/config_test.go (about)

     1  package googlecompute
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestConfigPrepare(t *testing.T) {
    12  	cases := []struct {
    13  		Key   string
    14  		Value interface{}
    15  		Err   bool
    16  	}{
    17  		{
    18  			"unknown_key",
    19  			"bad",
    20  			true,
    21  		},
    22  
    23  		{
    24  			"private_key_file",
    25  			"/tmp/i/should/not/exist",
    26  			true,
    27  		},
    28  
    29  		{
    30  			"project_id",
    31  			nil,
    32  			true,
    33  		},
    34  		{
    35  			"project_id",
    36  			"foo",
    37  			false,
    38  		},
    39  
    40  		{
    41  			"source_image",
    42  			nil,
    43  			true,
    44  		},
    45  		{
    46  			"source_image",
    47  			"foo",
    48  			false,
    49  		},
    50  
    51  		{
    52  			"source_image_family",
    53  			nil,
    54  			false,
    55  		},
    56  		{
    57  			"source_image_family",
    58  			"foo",
    59  			false,
    60  		},
    61  
    62  		{
    63  			"zone",
    64  			nil,
    65  			true,
    66  		},
    67  		{
    68  			"zone",
    69  			"foo",
    70  			false,
    71  		},
    72  
    73  		{
    74  			"ssh_timeout",
    75  			"SO BAD",
    76  			true,
    77  		},
    78  		{
    79  			"ssh_timeout",
    80  			"5s",
    81  			false,
    82  		},
    83  
    84  		{
    85  			"state_timeout",
    86  			"SO BAD",
    87  			true,
    88  		},
    89  		{
    90  			"state_timeout",
    91  			"5s",
    92  			false,
    93  		},
    94  		{
    95  			"use_internal_ip",
    96  			nil,
    97  			false,
    98  		},
    99  		{
   100  			"use_internal_ip",
   101  			false,
   102  			false,
   103  		},
   104  		{
   105  			"use_internal_ip",
   106  			"SO VERY BAD",
   107  			true,
   108  		},
   109  		{
   110  			"on_host_maintenance",
   111  			nil,
   112  			false,
   113  		},
   114  		{
   115  			"on_host_maintenance",
   116  			"TERMINATE",
   117  			false,
   118  		},
   119  		{
   120  			"on_host_maintenance",
   121  			"SO VERY BAD",
   122  			true,
   123  		},
   124  		{
   125  			"preemptible",
   126  			nil,
   127  			false,
   128  		},
   129  		{
   130  			"preemptible",
   131  			false,
   132  			false,
   133  		},
   134  		{
   135  			"preemptible",
   136  			"SO VERY BAD",
   137  			true,
   138  		},
   139  		{
   140  			"image_family",
   141  			nil,
   142  			false,
   143  		},
   144  		{
   145  			"image_family",
   146  			"",
   147  			false,
   148  		},
   149  		{
   150  			"image_family",
   151  			"foo-bar",
   152  			false,
   153  		},
   154  		{
   155  			"image_family",
   156  			"foo bar",
   157  			true,
   158  		},
   159  		{
   160  			"scopes",
   161  			[]string{},
   162  			false,
   163  		},
   164  		{
   165  			"scopes",
   166  			[]string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/sqlservice.admin"},
   167  			false,
   168  		},
   169  		{
   170  			"scopes",
   171  			[]string{"https://www.googleapis.com/auth/cloud-platform"},
   172  			false,
   173  		},
   174  
   175  		{
   176  			"disable_default_service_account",
   177  			"",
   178  			false,
   179  		},
   180  		{
   181  			"disable_default_service_account",
   182  			nil,
   183  			false,
   184  		},
   185  		{
   186  			"disable_default_service_account",
   187  			false,
   188  			false,
   189  		},
   190  		{
   191  			"disable_default_service_account",
   192  			true,
   193  			false,
   194  		},
   195  		{
   196  			"disable_default_service_account",
   197  			"NOT A BOOL",
   198  			true,
   199  		},
   200  	}
   201  
   202  	for _, tc := range cases {
   203  		raw, tempfile := testConfig(t)
   204  		defer os.Remove(tempfile)
   205  
   206  		if tc.Value == nil {
   207  			delete(raw, tc.Key)
   208  		} else {
   209  			raw[tc.Key] = tc.Value
   210  		}
   211  
   212  		_, warns, errs := NewConfig(raw)
   213  
   214  		if tc.Err {
   215  			testConfigErr(t, warns, errs, tc.Key)
   216  		} else {
   217  			testConfigOk(t, warns, errs)
   218  		}
   219  	}
   220  }
   221  
   222  func TestConfigPrepareAccelerator(t *testing.T) {
   223  	cases := []struct {
   224  		Keys   []string
   225  		Values []interface{}
   226  		Err    bool
   227  	}{
   228  		{
   229  			[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
   230  			[]interface{}{1, "MIGRATE", "something_valid"},
   231  			true,
   232  		},
   233  		{
   234  			[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
   235  			[]interface{}{1, "TERMINATE", "something_valid"},
   236  			false,
   237  		},
   238  		{
   239  			[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
   240  			[]interface{}{1, "TERMINATE", nil},
   241  			true,
   242  		},
   243  		{
   244  			[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
   245  			[]interface{}{1, "TERMINATE", ""},
   246  			true,
   247  		},
   248  		{
   249  			[]string{"accelerator_count", "on_host_maintenance", "accelerator_type"},
   250  			[]interface{}{1, "TERMINATE", "something_valid"},
   251  			false,
   252  		},
   253  	}
   254  
   255  	for _, tc := range cases {
   256  		raw, tempfile := testConfig(t)
   257  		defer os.Remove(tempfile)
   258  
   259  		errStr := ""
   260  		for k := range tc.Keys {
   261  
   262  			// Create the string for error reporting
   263  			// convert value to string if it can be converted
   264  			errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k])
   265  			if tc.Values[k] == nil {
   266  				delete(raw, tc.Keys[k])
   267  			} else {
   268  				raw[tc.Keys[k]] = tc.Values[k]
   269  			}
   270  		}
   271  
   272  		_, warns, errs := NewConfig(raw)
   273  
   274  		if tc.Err {
   275  			testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
   276  		} else {
   277  			testConfigOk(t, warns, errs)
   278  		}
   279  	}
   280  }
   281  
   282  func TestConfigPrepareServiceAccount(t *testing.T) {
   283  	cases := []struct {
   284  		Keys   []string
   285  		Values []interface{}
   286  		Err    bool
   287  	}{
   288  		{
   289  			[]string{"disable_default_service_account", "service_account_email"},
   290  			[]interface{}{true, "service@account.email.com"},
   291  			true,
   292  		},
   293  		{
   294  			[]string{"disable_default_service_account", "service_account_email"},
   295  			[]interface{}{false, "service@account.email.com"},
   296  			false,
   297  		},
   298  		{
   299  			[]string{"disable_default_service_account", "service_account_email"},
   300  			[]interface{}{true, ""},
   301  			false,
   302  		},
   303  	}
   304  
   305  	for _, tc := range cases {
   306  		raw, tempfile := testConfig(t)
   307  		defer os.Remove(tempfile)
   308  
   309  		errStr := ""
   310  		for k := range tc.Keys {
   311  
   312  			// Create the string for error reporting
   313  			// convert value to string if it can be converted
   314  			errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k])
   315  			if tc.Values[k] == nil {
   316  				delete(raw, tc.Keys[k])
   317  			} else {
   318  				raw[tc.Keys[k]] = tc.Values[k]
   319  			}
   320  		}
   321  
   322  		_, warns, errs := NewConfig(raw)
   323  
   324  		if tc.Err {
   325  			testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", "))
   326  		} else {
   327  			testConfigOk(t, warns, errs)
   328  		}
   329  	}
   330  }
   331  
   332  func TestConfigPrepareStartupScriptFile(t *testing.T) {
   333  	config := map[string]interface{}{
   334  		"project_id":          "project",
   335  		"source_image":        "foo",
   336  		"ssh_username":        "packer",
   337  		"startup_script_file": "no-such-file",
   338  		"zone":                "us-central1-a",
   339  	}
   340  
   341  	_, _, errs := NewConfig(config)
   342  
   343  	if errs == nil || !strings.Contains(errs.Error(), "startup_script_file") {
   344  		t.Fatalf("should error: startup_script_file")
   345  	}
   346  }
   347  
   348  func TestConfigDefaults(t *testing.T) {
   349  	cases := []struct {
   350  		Read  func(c *Config) interface{}
   351  		Value interface{}
   352  	}{
   353  		{
   354  			func(c *Config) interface{} { return c.Comm.Type },
   355  			"ssh",
   356  		},
   357  
   358  		{
   359  			func(c *Config) interface{} { return c.Comm.SSHPort },
   360  			22,
   361  		},
   362  	}
   363  
   364  	for _, tc := range cases {
   365  		raw, tempfile := testConfig(t)
   366  		defer os.Remove(tempfile)
   367  
   368  		c, warns, errs := NewConfig(raw)
   369  		testConfigOk(t, warns, errs)
   370  
   371  		actual := tc.Read(c)
   372  		if actual != tc.Value {
   373  			t.Fatalf("bad: %#v", actual)
   374  		}
   375  	}
   376  }
   377  
   378  func TestImageName(t *testing.T) {
   379  	raw, tempfile := testConfig(t)
   380  	defer os.Remove(tempfile)
   381  
   382  	c, _, _ := NewConfig(raw)
   383  	if !strings.HasPrefix(c.ImageName, "packer-") {
   384  		t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName)
   385  	}
   386  	if strings.Contains(c.ImageName, "{{timestamp}}") {
   387  		t.Errorf("ImageName should be interpolated; found %s", c.ImageName)
   388  	}
   389  }
   390  
   391  func TestRegion(t *testing.T) {
   392  	raw, tempfile := testConfig(t)
   393  	defer os.Remove(tempfile)
   394  
   395  	c, _, _ := NewConfig(raw)
   396  	if c.Region != "us-east1" {
   397  		t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region)
   398  	}
   399  }
   400  
   401  // Helper stuff below
   402  
   403  func testConfig(t *testing.T) (config map[string]interface{}, tempAccountFile string) {
   404  	tempAccountFile = testAccountFile(t)
   405  
   406  	config = map[string]interface{}{
   407  		"account_file": tempAccountFile,
   408  		"project_id":   "hashicorp",
   409  		"source_image": "foo",
   410  		"ssh_username": "root",
   411  		"image_family": "bar",
   412  		"image_labels": map[string]string{
   413  			"label-1": "value-1",
   414  			"label-2": "value-2",
   415  		},
   416  		"image_licenses": []string{
   417  			"test-license",
   418  		},
   419  		"zone": "us-east1-a",
   420  	}
   421  
   422  	return config, tempAccountFile
   423  }
   424  
   425  func testConfigStruct(t *testing.T) *Config {
   426  	raw, tempfile := testConfig(t)
   427  	defer os.Remove(tempfile)
   428  
   429  	c, warns, errs := NewConfig(raw)
   430  	if len(warns) > 0 {
   431  		t.Fatalf("bad: %#v", len(warns))
   432  	}
   433  	if errs != nil {
   434  		t.Fatalf("bad: %#v", errs)
   435  	}
   436  
   437  	return c
   438  }
   439  
   440  func testConfigErr(t *testing.T, warns []string, err error, extra string) {
   441  	if len(warns) > 0 {
   442  		t.Fatalf("bad: %#v", warns)
   443  	}
   444  	if err == nil {
   445  		t.Fatalf("should error: %s", extra)
   446  	}
   447  }
   448  
   449  func testConfigOk(t *testing.T, warns []string, err error) {
   450  	if len(warns) > 0 {
   451  		t.Fatalf("bad: %#v", warns)
   452  	}
   453  	if err != nil {
   454  		t.Fatalf("bad: %s", err)
   455  	}
   456  }
   457  
   458  func testAccountFile(t *testing.T) string {
   459  	tf, err := ioutil.TempFile("", "packer")
   460  	if err != nil {
   461  		t.Fatalf("err: %s", err)
   462  	}
   463  	defer tf.Close()
   464  
   465  	if _, err := tf.Write([]byte(testAccountContent)); err != nil {
   466  		t.Fatalf("err: %s", err)
   467  	}
   468  
   469  	return tf.Name()
   470  }
   471  
   472  // This is just some dummy data that doesn't actually work (it was revoked
   473  // a long time ago).
   474  const testAccountContent = `{}`