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