github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/joyent/config_test.go (about)

     1  // Copyright 2013 Joyent Inc.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package joyent_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  	envtesting "github.com/juju/juju/environs/testing"
    19  	jp "github.com/juju/juju/provider/joyent"
    20  	coretesting "github.com/juju/juju/testing"
    21  	"github.com/juju/juju/utils/ssh"
    22  )
    23  
    24  func newConfig(c *gc.C, attrs coretesting.Attrs) *config.Config {
    25  	attrs = coretesting.FakeConfig().Merge(attrs)
    26  	cfg, err := config.New(config.UseDefaults, attrs)
    27  	c.Assert(err, jc.ErrorIsNil)
    28  	return cfg
    29  }
    30  
    31  func validAttrs() coretesting.Attrs {
    32  	return coretesting.FakeConfig().Merge(coretesting.Attrs{
    33  		"type":             "joyent",
    34  		"sdc-user":         "test",
    35  		"sdc-key-id":       "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff",
    36  		"sdc-url":          "test://test.api.joyentcloud.com",
    37  		"manta-user":       "test",
    38  		"manta-key-id":     "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff",
    39  		"manta-url":        "test://test.manta.joyent.com",
    40  		"private-key-path": "~/.ssh/provider_id_rsa",
    41  		"algorithm":        "rsa-sha256",
    42  		"control-dir":      "juju-test",
    43  	})
    44  }
    45  
    46  type ConfigSuite struct {
    47  	coretesting.FakeJujuHomeSuite
    48  	originalValues map[string]testing.Restorer
    49  	privateKeyData string
    50  }
    51  
    52  var _ = gc.Suite(&ConfigSuite{})
    53  
    54  func (s *ConfigSuite) SetUpSuite(c *gc.C) {
    55  	s.FakeJujuHomeSuite.SetUpSuite(c)
    56  	restoreSdcAccount := testing.PatchEnvironment(jp.SdcAccount, "tester")
    57  	s.AddSuiteCleanup(func(*gc.C) { restoreSdcAccount() })
    58  	restoreSdcKeyId := testing.PatchEnvironment(jp.SdcKeyId, "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00")
    59  	s.AddSuiteCleanup(func(*gc.C) { restoreSdcKeyId() })
    60  	restoreMantaUser := testing.PatchEnvironment(jp.MantaUser, "tester")
    61  	s.AddSuiteCleanup(func(*gc.C) { restoreMantaUser() })
    62  	restoreMantaKeyId := testing.PatchEnvironment(jp.MantaKeyId, "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00")
    63  	s.AddSuiteCleanup(func(*gc.C) { restoreMantaKeyId() })
    64  	s.privateKeyData = generatePrivateKey(c)
    65  	jp.RegisterMachinesEndpoint()
    66  	s.AddSuiteCleanup(func(*gc.C) { jp.UnregisterMachinesEndpoint() })
    67  }
    68  
    69  func generatePrivateKey(c *gc.C) string {
    70  	oldBits := ssh.KeyBits
    71  	defer func() {
    72  		ssh.KeyBits = oldBits
    73  	}()
    74  	ssh.KeyBits = 32
    75  	private, _, err := ssh.GenerateKey("test-client")
    76  	c.Assert(err, jc.ErrorIsNil)
    77  	return private
    78  }
    79  
    80  func (s *ConfigSuite) SetUpTest(c *gc.C) {
    81  	s.FakeJujuHomeSuite.SetUpTest(c)
    82  	s.AddCleanup(CreateTestKey(c))
    83  	for _, envVar := range jp.EnvironmentVariables {
    84  		s.PatchEnvironment(envVar, "")
    85  	}
    86  }
    87  
    88  var newConfigTests = []struct {
    89  	info    string
    90  	insert  coretesting.Attrs
    91  	remove  []string
    92  	envVars map[string]string
    93  	expect  coretesting.Attrs
    94  	err     string
    95  }{{
    96  	info:   "sdc-user is required",
    97  	remove: []string{"sdc-user"},
    98  	err:    ".* cannot get sdc-user value from environment variable .*",
    99  }, {
   100  	info:   "sdc-user cannot be empty",
   101  	insert: coretesting.Attrs{"sdc-user": ""},
   102  	err:    ".* cannot get sdc-user value from environment variable .*",
   103  }, {
   104  	info:   "can get sdc-user from env variable",
   105  	insert: coretesting.Attrs{"sdc-user": ""},
   106  	expect: coretesting.Attrs{"sdc-user": "tester"},
   107  	envVars: map[string]string{
   108  		"SDC_ACCOUNT": "tester",
   109  	},
   110  }, {
   111  	info:   "can get sdc-user from env variable, missing from config",
   112  	remove: []string{"sdc-user"},
   113  	expect: coretesting.Attrs{"sdc-user": "tester"},
   114  	envVars: map[string]string{
   115  		"SDC_ACCOUNT": "tester",
   116  	},
   117  }, {
   118  	info:   "sdc-key-id is required",
   119  	remove: []string{"sdc-key-id"},
   120  	err:    ".* cannot get sdc-key-id value from environment variable .*",
   121  }, {
   122  	info:   "sdc-key-id cannot be empty",
   123  	insert: coretesting.Attrs{"sdc-key-id": ""},
   124  	err:    ".* cannot get sdc-key-id value from environment variable .*",
   125  }, {
   126  	info:   "can get sdc-key-id from env variable",
   127  	insert: coretesting.Attrs{"sdc-key-id": ""},
   128  	expect: coretesting.Attrs{"sdc-key-id": "key"},
   129  	envVars: map[string]string{
   130  		"SDC_KEY_ID": "key",
   131  	},
   132  }, {
   133  	info:   "can get sdc-key-id from env variable, missing from config",
   134  	remove: []string{"sdc-key-id"},
   135  	expect: coretesting.Attrs{"sdc-key-id": "key"},
   136  	envVars: map[string]string{
   137  		"SDC_KEY_ID": "key",
   138  	},
   139  }, {
   140  	info:   "sdc-url is inserted if missing",
   141  	expect: coretesting.Attrs{"sdc-url": "test://test.api.joyentcloud.com"},
   142  }, {
   143  	info:   "sdc-url cannot be empty",
   144  	insert: coretesting.Attrs{"sdc-url": ""},
   145  	err:    ".* cannot get sdc-url value from environment variable .*",
   146  }, {
   147  	info:   "sdc-url is untouched if present",
   148  	insert: coretesting.Attrs{"sdc-url": "test://test.api.joyentcloud.com"},
   149  	expect: coretesting.Attrs{"sdc-url": "test://test.api.joyentcloud.com"},
   150  }, {
   151  	info:   "manta-user is required",
   152  	remove: []string{"manta-user"},
   153  	err:    ".* cannot get manta-user value from environment variable .*",
   154  }, {
   155  	info:   "manta-user cannot be empty",
   156  	insert: coretesting.Attrs{"manta-user": ""},
   157  	err:    ".* cannot get manta-user value from environment variable .*",
   158  }, {
   159  	info:   "can get manta-user from env variable",
   160  	insert: coretesting.Attrs{"manta-user": ""},
   161  	expect: coretesting.Attrs{"manta-user": "tester"},
   162  	envVars: map[string]string{
   163  		"MANTA_USER": "tester",
   164  	},
   165  }, {
   166  	info:   "can get manta-user from env variable, missing from config",
   167  	remove: []string{"manta-user"},
   168  	expect: coretesting.Attrs{"manta-user": "tester"},
   169  	envVars: map[string]string{
   170  		"MANTA_USER": "tester",
   171  	},
   172  }, {
   173  	info:   "manta-key-id is required",
   174  	remove: []string{"manta-key-id"},
   175  	err:    ".* cannot get manta-key-id value from environment variable .*",
   176  }, {
   177  	info:   "manta-key-id cannot be empty",
   178  	insert: coretesting.Attrs{"manta-key-id": ""},
   179  	err:    ".* cannot get manta-key-id value from environment variable .*",
   180  }, {
   181  	info:   "can get manta-key-id from env variable",
   182  	insert: coretesting.Attrs{"manta-key-id": ""},
   183  	expect: coretesting.Attrs{"manta-key-id": "key"},
   184  	envVars: map[string]string{
   185  		"MANTA_KEY_ID": "key",
   186  	},
   187  }, {
   188  	info:   "can get manta-key-id from env variable, missing from config",
   189  	remove: []string{"manta-key-id"},
   190  	expect: coretesting.Attrs{"manta-key-id": "key"},
   191  	envVars: map[string]string{
   192  		"MANTA_KEY_ID": "key",
   193  	},
   194  }, {
   195  	info:   "manta-url is inserted if missing",
   196  	expect: coretesting.Attrs{"manta-url": "test://test.manta.joyent.com"},
   197  }, {
   198  	info:   "manta-url cannot be empty",
   199  	insert: coretesting.Attrs{"manta-url": ""},
   200  	err:    ".* cannot get manta-url value from environment variable .*",
   201  }, {
   202  	info:   "manta-url is untouched if present",
   203  	insert: coretesting.Attrs{"manta-url": "test://test.manta.joyent.com"},
   204  	expect: coretesting.Attrs{"manta-url": "test://test.manta.joyent.com"},
   205  }, {
   206  	info:   "private-key-path is inserted if missing",
   207  	remove: []string{"private-key-path"},
   208  	expect: coretesting.Attrs{"private-key-path": "~/.ssh/id_rsa"},
   209  }, {
   210  	info:   "can get private-key-path from env variable",
   211  	insert: coretesting.Attrs{"private-key-path": ""},
   212  	expect: coretesting.Attrs{"private-key-path": "some-file"},
   213  	envVars: map[string]string{
   214  		"MANTA_PRIVATE_KEY_FILE": "some-file",
   215  	},
   216  }, {
   217  	info:   "can get private-key-path from env variable, missing from config",
   218  	remove: []string{"private-key-path"},
   219  	expect: coretesting.Attrs{"private-key-path": "some-file"},
   220  	envVars: map[string]string{
   221  		"MANTA_PRIVATE_KEY_FILE": "some-file",
   222  	},
   223  }, {
   224  	info:   "algorithm is inserted if missing",
   225  	expect: coretesting.Attrs{"algorithm": "rsa-sha256"},
   226  }, {
   227  	info:   "algorithm cannot be empty",
   228  	insert: coretesting.Attrs{"algorithm": ""},
   229  	err:    ".* algorithm: must not be empty",
   230  }, {
   231  	info:   "unknown field is not touched",
   232  	insert: coretesting.Attrs{"unknown-field": 12345},
   233  	expect: coretesting.Attrs{"unknown-field": 12345},
   234  }}
   235  
   236  func (s *ConfigSuite) TestNewEnvironConfig(c *gc.C) {
   237  	for i, test := range newConfigTests {
   238  		c.Logf("test %d: %s", i, test.info)
   239  		for k, v := range test.envVars {
   240  			os.Setenv(k, v)
   241  		}
   242  		attrs := validAttrs().Merge(test.insert).Delete(test.remove...)
   243  		attrs["private-key"] = s.privateKeyData
   244  		testConfig := newConfig(c, attrs)
   245  		environ, err := environs.New(testConfig)
   246  		if test.err == "" {
   247  			c.Check(err, jc.ErrorIsNil)
   248  			if err != nil {
   249  				continue
   250  			}
   251  			attrs := environ.Config().AllAttrs()
   252  			for field, value := range test.expect {
   253  				c.Check(attrs[field], gc.Equals, value)
   254  			}
   255  		} else {
   256  			c.Check(environ, gc.IsNil)
   257  			c.Check(err, gc.ErrorMatches, test.err)
   258  		}
   259  	}
   260  }
   261  
   262  var changeConfigTests = []struct {
   263  	info   string
   264  	insert coretesting.Attrs
   265  	remove []string
   266  	expect coretesting.Attrs
   267  	err    string
   268  }{{
   269  	info:   "no change, no error",
   270  	expect: validAttrs(),
   271  }, {
   272  	info:   "can change sdc-user",
   273  	insert: coretesting.Attrs{"sdc-user": "joyent_user"},
   274  	expect: coretesting.Attrs{"sdc-user": "joyent_user"},
   275  }, {
   276  	info:   "can change sdc-key-id",
   277  	insert: coretesting.Attrs{"sdc-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"},
   278  	expect: coretesting.Attrs{"sdc-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"},
   279  }, {
   280  	info:   "can change sdc-url",
   281  	insert: coretesting.Attrs{"sdc-url": "test://test.api.joyentcloud.com"},
   282  	expect: coretesting.Attrs{"sdc-url": "test://test.api.joyentcloud.com"},
   283  }, {
   284  	info:   "can change manta-user",
   285  	insert: coretesting.Attrs{"manta-user": "manta_user"},
   286  	expect: coretesting.Attrs{"manta-user": "manta_user"},
   287  }, {
   288  	info:   "can change manta-key-id",
   289  	insert: coretesting.Attrs{"manta-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"},
   290  	expect: coretesting.Attrs{"manta-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"},
   291  }, {
   292  	info:   "can change manta-url",
   293  	insert: coretesting.Attrs{"manta-url": "test://test.manta.joyent.com"},
   294  	expect: coretesting.Attrs{"manta-url": "test://test.manta.joyent.com"},
   295  }, {
   296  	info:   "can insert unknown field",
   297  	insert: coretesting.Attrs{"unknown": "ignoti"},
   298  	expect: coretesting.Attrs{"unknown": "ignoti"},
   299  }}
   300  
   301  func (s *ConfigSuite) TestValidateChange(c *gc.C) {
   302  	attrs := validAttrs()
   303  	attrs["private-key"] = s.privateKeyData
   304  	baseConfig := newConfig(c, attrs)
   305  	for i, test := range changeConfigTests {
   306  		c.Logf("test %d: %s", i, test.info)
   307  		attrs := validAttrs().Merge(test.insert).Delete(test.remove...)
   308  		attrs["private-key"] = s.privateKeyData
   309  		testConfig := newConfig(c, attrs)
   310  		validatedConfig, err := jp.Provider.Validate(testConfig, baseConfig)
   311  		if test.err == "" {
   312  			c.Check(err, jc.ErrorIsNil)
   313  			if err != nil {
   314  				continue
   315  			}
   316  			attrs := validatedConfig.AllAttrs()
   317  			for field, value := range test.expect {
   318  				c.Check(attrs[field], gc.Equals, value)
   319  			}
   320  		} else {
   321  			c.Check(validatedConfig, gc.IsNil)
   322  			c.Check(err, gc.ErrorMatches, "invalid config change: "+test.err)
   323  		}
   324  	}
   325  }
   326  
   327  func (s *ConfigSuite) TestSetConfig(c *gc.C) {
   328  	baseConfig := newConfig(c, validAttrs())
   329  	for i, test := range changeConfigTests {
   330  		c.Logf("test %d: %s", i, test.info)
   331  		environ, err := environs.New(baseConfig)
   332  		c.Assert(err, jc.ErrorIsNil)
   333  		attrs := validAttrs().Merge(test.insert).Delete(test.remove...)
   334  		testConfig := newConfig(c, attrs)
   335  		err = environ.SetConfig(testConfig)
   336  		newAttrs := environ.Config().AllAttrs()
   337  		if test.err == "" {
   338  			c.Check(err, jc.ErrorIsNil)
   339  			for field, value := range test.expect {
   340  				c.Check(newAttrs[field], gc.Equals, value)
   341  			}
   342  		} else {
   343  			c.Check(err, gc.ErrorMatches, test.err)
   344  			for field, value := range baseConfig.UnknownAttrs() {
   345  				c.Check(newAttrs[field], gc.Equals, value)
   346  			}
   347  		}
   348  	}
   349  }
   350  
   351  func validPrepareAttrs() coretesting.Attrs {
   352  	return validAttrs().Delete("private-key")
   353  }
   354  
   355  var prepareConfigTests = []struct {
   356  	info   string
   357  	insert coretesting.Attrs
   358  	remove []string
   359  	expect coretesting.Attrs
   360  	err    string
   361  }{{
   362  	info:   "All value provided, nothig to do",
   363  	expect: validPrepareAttrs(),
   364  }, {
   365  	info:   "private key is loaded from key file",
   366  	insert: coretesting.Attrs{"private-key-path": fmt.Sprintf("~/.ssh/%s", testKeyFileName)},
   367  	expect: coretesting.Attrs{"private-key": testPrivateKey},
   368  }, {
   369  	info:   "bad private-key-path errors, not panics",
   370  	insert: coretesting.Attrs{"private-key-path": "~/.ssh/no-such-file"},
   371  	err:    "invalid Joyent provider config: open .*: " + utils.NoSuchFileErrRegexp,
   372  }}
   373  
   374  func (s *ConfigSuite) TestPrepareForBootstrap(c *gc.C) {
   375  	ctx := envtesting.BootstrapContext(c)
   376  	for i, test := range prepareConfigTests {
   377  		c.Logf("test %d: %s", i, test.info)
   378  		attrs := validPrepareAttrs().Merge(test.insert).Delete(test.remove...)
   379  		testConfig := newConfig(c, attrs)
   380  		preparedConfig, err := jp.Provider.PrepareForBootstrap(ctx, testConfig)
   381  		if test.err == "" {
   382  			c.Check(err, jc.ErrorIsNil)
   383  			attrs := preparedConfig.Config().AllAttrs()
   384  			for field, value := range test.expect {
   385  				c.Check(attrs[field], gc.Equals, value)
   386  			}
   387  		} else {
   388  			c.Check(preparedConfig, gc.IsNil)
   389  			c.Check(err, gc.ErrorMatches, test.err)
   390  		}
   391  	}
   392  }
   393  
   394  func (s *ConfigSuite) TestPrepareWithDefaultKeyFile(c *gc.C) {
   395  	ctx := envtesting.BootstrapContext(c)
   396  	// By default "private-key-path isn't set until after validateConfig has been called.
   397  	attrs := validAttrs().Delete("private-key-path", "private-key")
   398  	keyFilePath, err := utils.NormalizePath(jp.DefaultPrivateKey)
   399  	c.Assert(err, jc.ErrorIsNil)
   400  	err = ioutil.WriteFile(keyFilePath, []byte(testPrivateKey), 400)
   401  	c.Assert(err, jc.ErrorIsNil)
   402  	defer os.Remove(keyFilePath)
   403  	testConfig := newConfig(c, attrs)
   404  	preparedConfig, err := jp.Provider.PrepareForBootstrap(ctx, testConfig)
   405  	c.Assert(err, jc.ErrorIsNil)
   406  	attrs = preparedConfig.Config().AllAttrs()
   407  	c.Check(attrs["private-key-path"], gc.Equals, jp.DefaultPrivateKey)
   408  	c.Check(attrs["private-key"], gc.Equals, testPrivateKey)
   409  }