github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/ec2/config_test.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  // TODO: Clean this up so it matches environs/openstack/config_test.go.
     7  
     8  import (
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils"
    16  	"gopkg.in/amz.v3/aws"
    17  	gc "gopkg.in/check.v1"
    18  
    19  	"github.com/juju/juju/cloud"
    20  	"github.com/juju/juju/environs"
    21  	"github.com/juju/juju/environs/config"
    22  	"github.com/juju/juju/testing"
    23  )
    24  
    25  // Use local suite since this file lives in the ec2 package
    26  // for testing internals.
    27  type ConfigSuite struct {
    28  	testing.BaseSuite
    29  	savedHome, savedAccessKey, savedSecretKey string
    30  }
    31  
    32  var _ = gc.Suite(&ConfigSuite{})
    33  
    34  var configTestRegion = aws.Region{
    35  	Name:        "configtest",
    36  	EC2Endpoint: "testregion.nowhere:1234",
    37  }
    38  
    39  var testAuth = aws.Auth{
    40  	AccessKey: "gopher",
    41  	SecretKey: "long teeth",
    42  }
    43  
    44  // configTest specifies a config parsing test, checking that env when
    45  // parsed as the ec2 section of a config file matches baseConfigResult
    46  // when mutated by the mutate function, or that the parse matches the
    47  // given error.
    48  type configTest struct {
    49  	config             map[string]interface{}
    50  	change             map[string]interface{}
    51  	expect             map[string]interface{}
    52  	region             string
    53  	vpcID              string
    54  	forceVPCID         bool
    55  	accessKey          string
    56  	secretKey          string
    57  	firewallMode       string
    58  	blockStorageSource string
    59  	err                string
    60  }
    61  
    62  type attrs map[string]interface{}
    63  
    64  func (t configTest) check(c *gc.C) {
    65  	attrs := testing.FakeConfig().Merge(testing.Attrs{
    66  		"type": "ec2",
    67  	}).Merge(t.config)
    68  	cfg, err := config.New(config.NoDefaults, attrs)
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	e, err := environs.New(cfg)
    71  	if t.change != nil {
    72  		c.Assert(err, jc.ErrorIsNil)
    73  
    74  		// Testing a change in configuration.
    75  		var old, changed, valid *config.Config
    76  		ec2env := e.(*environ)
    77  		old = ec2env.ecfg().Config
    78  		changed, err = old.Apply(t.change)
    79  		c.Assert(err, jc.ErrorIsNil)
    80  
    81  		// Keep err for validation below.
    82  		valid, err = providerInstance.Validate(changed, old)
    83  		if err == nil {
    84  			err = ec2env.SetConfig(valid)
    85  		}
    86  	}
    87  	if t.err != "" {
    88  		c.Check(err, gc.ErrorMatches, t.err)
    89  		return
    90  	}
    91  	c.Assert(err, jc.ErrorIsNil)
    92  
    93  	ecfg := e.(*environ).ecfg()
    94  	c.Assert(ecfg.Name(), gc.Equals, "testenv")
    95  	if t.region != "" {
    96  		c.Assert(ecfg.region(), gc.Equals, t.region)
    97  	}
    98  
    99  	c.Assert(ecfg.vpcID(), gc.Equals, t.vpcID)
   100  	c.Assert(ecfg.forceVPCID(), gc.Equals, t.forceVPCID)
   101  
   102  	if t.accessKey != "" {
   103  		c.Assert(ecfg.accessKey(), gc.Equals, t.accessKey)
   104  		c.Assert(ecfg.secretKey(), gc.Equals, t.secretKey)
   105  		expected := map[string]string{
   106  			"access-key": t.accessKey,
   107  			"secret-key": t.secretKey,
   108  		}
   109  		c.Assert(err, jc.ErrorIsNil)
   110  		actual, err := e.Provider().SecretAttrs(ecfg.Config)
   111  		c.Assert(err, jc.ErrorIsNil)
   112  		c.Assert(expected, gc.DeepEquals, actual)
   113  	} else {
   114  		c.Assert(ecfg.accessKey(), gc.DeepEquals, testAuth.AccessKey)
   115  		c.Assert(ecfg.secretKey(), gc.DeepEquals, testAuth.SecretKey)
   116  	}
   117  	if t.firewallMode != "" {
   118  		c.Assert(ecfg.FirewallMode(), gc.Equals, t.firewallMode)
   119  	}
   120  	for name, expect := range t.expect {
   121  		actual, found := ecfg.UnknownAttrs()[name]
   122  		c.Check(found, jc.IsTrue)
   123  		c.Check(actual, gc.Equals, expect)
   124  	}
   125  }
   126  
   127  var configTests = []configTest{
   128  	{
   129  		config: attrs{},
   130  	}, {
   131  		// check that region defaults to us-east-1
   132  		config: attrs{},
   133  		region: "us-east-1",
   134  	}, {
   135  		config: attrs{
   136  			"region": "eu-west-1",
   137  		},
   138  		region: "eu-west-1",
   139  	}, {
   140  		config: attrs{
   141  			"region": "unknown",
   142  		},
   143  		err: ".*invalid region name.*",
   144  	}, {
   145  		config: attrs{
   146  			"region": "configtest",
   147  		},
   148  		region: "configtest",
   149  	}, {
   150  		config: attrs{
   151  			"region": "configtest",
   152  		},
   153  		change: attrs{
   154  			"region": "us-east-1",
   155  		},
   156  		err: `.*cannot change region from "configtest" to "us-east-1"`,
   157  	}, {
   158  		config: attrs{
   159  			"region": 666,
   160  		},
   161  		err: `.*expected string, got int\(666\)`,
   162  	}, {
   163  		config:     attrs{},
   164  		vpcID:      "",
   165  		forceVPCID: false,
   166  	}, {
   167  		config: attrs{
   168  			"vpc-id": "invalid",
   169  		},
   170  		err:        `.*vpc-id: "invalid" is not a valid AWS VPC ID`,
   171  		vpcID:      "",
   172  		forceVPCID: false,
   173  	}, {
   174  		config: attrs{
   175  			"vpc-id": 42,
   176  		},
   177  		err:        `.*expected string, got int\(42\)`,
   178  		vpcID:      "",
   179  		forceVPCID: false,
   180  	}, {
   181  		config: attrs{
   182  			"vpc-id-force": "nonsense",
   183  		},
   184  		err:        `.*expected bool, got string\("nonsense"\)`,
   185  		vpcID:      "",
   186  		forceVPCID: false,
   187  	}, {
   188  		config: attrs{
   189  			"vpc-id":       "vpc-anything",
   190  			"vpc-id-force": 999,
   191  		},
   192  		err:        `.*expected bool, got int\(999\)`,
   193  		vpcID:      "",
   194  		forceVPCID: false,
   195  	}, {
   196  		config: attrs{
   197  			"vpc-id":       "",
   198  			"vpc-id-force": true,
   199  		},
   200  		err:        `.*cannot use vpc-id-force without specifying vpc-id as well`,
   201  		vpcID:      "",
   202  		forceVPCID: true,
   203  	}, {
   204  		config: attrs{
   205  			"vpc-id": "vpc-a1b2c3d4",
   206  		},
   207  		vpcID:      "vpc-a1b2c3d4",
   208  		forceVPCID: false,
   209  	}, {
   210  		config: attrs{
   211  			"vpc-id":       "vpc-some-id",
   212  			"vpc-id-force": true,
   213  		},
   214  		vpcID:      "vpc-some-id",
   215  		forceVPCID: true,
   216  	}, {
   217  		config: attrs{
   218  			"vpc-id":       "vpc-abcd",
   219  			"vpc-id-force": false,
   220  		},
   221  		vpcID:      "vpc-abcd",
   222  		forceVPCID: false,
   223  	}, {
   224  		config: attrs{
   225  			"vpc-id":       "vpc-unchanged",
   226  			"vpc-id-force": true,
   227  		},
   228  		change: attrs{
   229  			"vpc-id":       "vpc-unchanged",
   230  			"vpc-id-force": false,
   231  		},
   232  		err:        `.*cannot change vpc-id-force from true to false`,
   233  		vpcID:      "vpc-unchanged",
   234  		forceVPCID: true,
   235  	}, {
   236  		config: attrs{
   237  			"vpc-id": "",
   238  		},
   239  		change: attrs{
   240  			"vpc-id": "vpc-changed",
   241  		},
   242  		err:        `.*cannot change vpc-id from "" to "vpc-changed"`,
   243  		vpcID:      "",
   244  		forceVPCID: false,
   245  	}, {
   246  		config: attrs{
   247  			"vpc-id": "vpc-initial",
   248  		},
   249  		change: attrs{
   250  			"vpc-id": "",
   251  		},
   252  		err:        `.*cannot change vpc-id from "vpc-initial" to ""`,
   253  		vpcID:      "vpc-initial",
   254  		forceVPCID: false,
   255  	}, {
   256  		config: attrs{
   257  			"vpc-id": "vpc-old",
   258  		},
   259  		change: attrs{
   260  			"vpc-id": "vpc-new",
   261  		},
   262  		err:        `.*cannot change vpc-id from "vpc-old" to "vpc-new"`,
   263  		vpcID:      "vpc-old",
   264  		forceVPCID: false,
   265  	}, {
   266  		config: attrs{
   267  			"vpc-id":       "vpc-foo",
   268  			"vpc-id-force": true,
   269  		},
   270  		change:     attrs{},
   271  		vpcID:      "vpc-foo",
   272  		forceVPCID: true,
   273  	}, {
   274  		config: attrs{
   275  			"access-key": 666,
   276  		},
   277  		err: `.*expected string, got int\(666\)`,
   278  	}, {
   279  		config: attrs{
   280  			"secret-key": 666,
   281  		},
   282  		err: `.*expected string, got int\(666\)`,
   283  	}, {
   284  		config: attrs{
   285  			"access-key": "jujuer",
   286  			"secret-key": "open sesame",
   287  		},
   288  		accessKey: "jujuer",
   289  		secretKey: "open sesame",
   290  	}, {
   291  		config: attrs{
   292  			"access-key": "jujuer",
   293  		},
   294  		err: ".*model has no access-key or secret-key",
   295  	}, {
   296  		config: attrs{
   297  			"secret-key": "badness",
   298  		},
   299  		err: ".*model has no access-key or secret-key",
   300  	}, {
   301  		config: attrs{
   302  			"admin-secret": "Futumpsh",
   303  		},
   304  	}, {
   305  		config:       attrs{},
   306  		firewallMode: config.FwInstance,
   307  	}, {
   308  		config:             attrs{},
   309  		blockStorageSource: "ebs",
   310  	}, {
   311  		config: attrs{
   312  			"storage-default-block-source": "ebs-fast",
   313  		},
   314  		blockStorageSource: "ebs-fast",
   315  	}, {
   316  		config: attrs{
   317  			"firewall-mode": "instance",
   318  		},
   319  		firewallMode: config.FwInstance,
   320  	}, {
   321  		config: attrs{
   322  			"firewall-mode": "global",
   323  		},
   324  		firewallMode: config.FwGlobal,
   325  	}, {
   326  		config: attrs{
   327  			"firewall-mode": "none",
   328  		},
   329  		firewallMode: config.FwNone,
   330  	}, {
   331  		config: attrs{
   332  			"ssl-hostname-verification": false,
   333  		},
   334  		err: ".*disabling ssh-hostname-verification is not supported",
   335  	}, {
   336  		config: attrs{
   337  			"future": "hammerstein",
   338  		},
   339  		expect: attrs{
   340  			"future": "hammerstein",
   341  		},
   342  	}, {
   343  		change: attrs{
   344  			"future": "hammerstein",
   345  		},
   346  		expect: attrs{
   347  			"future": "hammerstein",
   348  		},
   349  	},
   350  }
   351  
   352  func indent(s string, with string) string {
   353  	var r string
   354  	lines := strings.Split(s, "\n")
   355  	for _, l := range lines {
   356  		r += with + l + "\n"
   357  	}
   358  	return r
   359  }
   360  
   361  func (s *ConfigSuite) SetUpTest(c *gc.C) {
   362  	s.BaseSuite.SetUpTest(c)
   363  	s.savedHome = utils.Home()
   364  	s.savedAccessKey = os.Getenv("AWS_ACCESS_KEY_ID")
   365  	s.savedSecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
   366  
   367  	home := c.MkDir()
   368  	sshDir := filepath.Join(home, ".ssh")
   369  	err := os.Mkdir(sshDir, 0777)
   370  	c.Assert(err, jc.ErrorIsNil)
   371  	err = ioutil.WriteFile(filepath.Join(sshDir, "id_rsa.pub"), []byte("sshkey\n"), 0666)
   372  	c.Assert(err, jc.ErrorIsNil)
   373  
   374  	err = utils.SetHome(home)
   375  	c.Assert(err, jc.ErrorIsNil)
   376  	os.Setenv("AWS_ACCESS_KEY_ID", testAuth.AccessKey)
   377  	os.Setenv("AWS_SECRET_ACCESS_KEY", testAuth.SecretKey)
   378  	aws.Regions["configtest"] = configTestRegion
   379  }
   380  
   381  func (s *ConfigSuite) TearDownTest(c *gc.C) {
   382  	err := utils.SetHome(s.savedHome)
   383  	c.Assert(err, jc.ErrorIsNil)
   384  	os.Setenv("AWS_ACCESS_KEY_ID", s.savedAccessKey)
   385  	os.Setenv("AWS_SECRET_ACCESS_KEY", s.savedSecretKey)
   386  	delete(aws.Regions, "configtest")
   387  	s.BaseSuite.TearDownTest(c)
   388  }
   389  
   390  func (s *ConfigSuite) TestConfig(c *gc.C) {
   391  	for i, t := range configTests {
   392  		c.Logf("test %d: %v", i, t.config)
   393  		t.check(c)
   394  	}
   395  }
   396  
   397  func (s *ConfigSuite) TestMissingAuth(c *gc.C) {
   398  	os.Setenv("AWS_ACCESS_KEY_ID", "")
   399  	os.Setenv("AWS_SECRET_ACCESS_KEY", "")
   400  
   401  	// Since PR #52 amz.v3 uses these AWS_ vars as fallbacks, if set.
   402  	os.Setenv("AWS_ACCESS_KEY", "")
   403  	os.Setenv("AWS_SECRET_KEY", "")
   404  
   405  	// Since LP r37 goamz uses also these EC2_ as fallbacks, so unset them too.
   406  	os.Setenv("EC2_ACCESS_KEY", "")
   407  	os.Setenv("EC2_SECRET_KEY", "")
   408  	test := configTests[0]
   409  	test.err = ".*model has no access-key or secret-key"
   410  	test.check(c)
   411  }
   412  
   413  func (s *ConfigSuite) TestBootstrapConfigSetsDefaultBlockSource(c *gc.C) {
   414  	s.PatchValue(&verifyCredentials, func(*environ) error { return nil })
   415  	attrs := testing.FakeConfig().Merge(testing.Attrs{
   416  		"type": "ec2",
   417  	})
   418  	cfg, err := config.New(config.NoDefaults, attrs)
   419  	c.Assert(err, jc.ErrorIsNil)
   420  
   421  	cfg, err = providerInstance.BootstrapConfig(environs.BootstrapConfigParams{
   422  		Config: cfg,
   423  		Credentials: cloud.NewCredential(
   424  			cloud.AccessKeyAuthType,
   425  			map[string]string{
   426  				"access-key": "x",
   427  				"secret-key": "y",
   428  			},
   429  		),
   430  		CloudRegion: "test",
   431  	})
   432  	c.Assert(err, jc.ErrorIsNil)
   433  	source, ok := cfg.StorageDefaultBlockSource()
   434  	c.Assert(ok, jc.IsTrue)
   435  	c.Assert(source, gc.Equals, "ebs")
   436  }
   437  
   438  func (s *ConfigSuite) TestPrepareSetsDefaultBlockSource(c *gc.C) {
   439  	s.PatchValue(&verifyCredentials, func(*environ) error { return nil })
   440  	attrs := testing.FakeConfig().Merge(testing.Attrs{
   441  		"type": "ec2",
   442  	})
   443  	config, err := config.New(config.NoDefaults, attrs)
   444  	c.Assert(err, jc.ErrorIsNil)
   445  
   446  	cfg, err := providerInstance.BootstrapConfig(environs.BootstrapConfigParams{
   447  		Config:      config,
   448  		CloudRegion: "test",
   449  		Credentials: cloud.NewCredential(
   450  			cloud.AccessKeyAuthType,
   451  			map[string]string{
   452  				"access-key": "x",
   453  				"secret-key": "y",
   454  			},
   455  		),
   456  	})
   457  	c.Assert(err, jc.ErrorIsNil)
   458  
   459  	source, ok := cfg.StorageDefaultBlockSource()
   460  	c.Assert(ok, jc.IsTrue)
   461  	c.Assert(source, gc.Equals, "ebs")
   462  }
   463  
   464  func (*ConfigSuite) TestSchema(c *gc.C) {
   465  	fields := providerInstance.Schema()
   466  	// Check that all the fields defined in environs/config
   467  	// are in the returned schema.
   468  	globalFields, err := config.Schema(nil)
   469  	c.Assert(err, gc.IsNil)
   470  	for name, field := range globalFields {
   471  		c.Check(fields[name], jc.DeepEquals, field)
   472  	}
   473  }