launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/open_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package environs_test
     5  
     6  import (
     7  	"strings"
     8  
     9  	gc "launchpad.net/gocheck"
    10  
    11  	"launchpad.net/juju-core/cert"
    12  	"launchpad.net/juju-core/constraints"
    13  	"launchpad.net/juju-core/environs"
    14  	"launchpad.net/juju-core/environs/bootstrap"
    15  	"launchpad.net/juju-core/environs/config"
    16  	"launchpad.net/juju-core/environs/configstore"
    17  	envtesting "launchpad.net/juju-core/environs/testing"
    18  	"launchpad.net/juju-core/errors"
    19  	"launchpad.net/juju-core/provider/dummy"
    20  	"launchpad.net/juju-core/testing"
    21  	jc "launchpad.net/juju-core/testing/checkers"
    22  	"launchpad.net/juju-core/testing/testbase"
    23  )
    24  
    25  type OpenSuite struct {
    26  	testbase.LoggingSuite
    27  	envtesting.ToolsFixture
    28  }
    29  
    30  var _ = gc.Suite(&OpenSuite{})
    31  
    32  func (*OpenSuite) TearDownTest(c *gc.C) {
    33  	dummy.Reset()
    34  }
    35  
    36  func (*OpenSuite) TestNewDummyEnviron(c *gc.C) {
    37  	// matches *Settings.Map()
    38  	cfg, err := config.New(config.NoDefaults, dummySampleConfig())
    39  	c.Assert(err, gc.IsNil)
    40  	env, err := environs.Prepare(cfg, configstore.NewMem())
    41  	c.Assert(err, gc.IsNil)
    42  	envtesting.UploadFakeTools(c, env.Storage())
    43  	ctx := envtesting.NewBootstrapContext(testing.Context(c))
    44  	err = bootstrap.Bootstrap(ctx, env, constraints.Value{})
    45  	c.Assert(err, gc.IsNil)
    46  }
    47  
    48  func (*OpenSuite) TestNewUnknownEnviron(c *gc.C) {
    49  	attrs := dummySampleConfig().Merge(testing.Attrs{
    50  		"type": "wondercloud",
    51  	})
    52  	env, err := environs.NewFromAttrs(attrs)
    53  	c.Assert(err, gc.ErrorMatches, "no registered provider for.*")
    54  	c.Assert(env, gc.IsNil)
    55  }
    56  
    57  func (*OpenSuite) TestNewFromName(c *gc.C) {
    58  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
    59  	store := configstore.NewMem()
    60  	e, err := environs.PrepareFromName("erewhemos", store)
    61  	c.Assert(err, gc.IsNil)
    62  
    63  	e, err = environs.NewFromName("erewhemos", store)
    64  	c.Assert(err, gc.IsNil)
    65  	c.Assert(e.Name(), gc.Equals, "erewhemos")
    66  }
    67  
    68  func (*OpenSuite) TestNewFromNameWithInvalidInfo(c *gc.C) {
    69  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
    70  	store := configstore.NewMem()
    71  	cfg, _, err := environs.ConfigForName("erewhemos", store)
    72  	c.Assert(err, gc.IsNil)
    73  	info, err := store.CreateInfo("erewhemos")
    74  	c.Assert(err, gc.IsNil)
    75  
    76  	// The configuration from environments.yaml is invalid
    77  	// because it doesn't contain the state-id attribute which
    78  	// the dummy environment adds at Prepare time.
    79  	info.SetBootstrapConfig(cfg.AllAttrs())
    80  	err = info.Write()
    81  	c.Assert(err, gc.IsNil)
    82  
    83  	e, err := environs.NewFromName("erewhemos", store)
    84  	c.Assert(err, gc.ErrorMatches, "environment is not prepared")
    85  	c.Assert(e, gc.IsNil)
    86  }
    87  
    88  func (*OpenSuite) TestNewFromNameWithInvalidEnvironConfig(c *gc.C) {
    89  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
    90  	store := configstore.NewMem()
    91  
    92  	e, err := environs.NewFromName("erewhemos", store)
    93  	c.Assert(err, gc.Equals, environs.ErrNotBootstrapped)
    94  	c.Assert(e, gc.IsNil)
    95  }
    96  
    97  func (*OpenSuite) TestPrepareFromName(c *gc.C) {
    98  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
    99  	e, err := environs.PrepareFromName("erewhemos", configstore.NewMem())
   100  	c.Assert(err, gc.IsNil)
   101  	c.Assert(e.Name(), gc.Equals, "erewhemos")
   102  	// Check we can access storage ok, which implies the environment has been prepared.
   103  	c.Assert(e.Storage(), gc.NotNil)
   104  }
   105  
   106  func (*OpenSuite) TestConfigForName(c *gc.C) {
   107  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
   108  	cfg, source, err := environs.ConfigForName("erewhemos", configstore.NewMem())
   109  	c.Assert(err, gc.IsNil)
   110  	c.Assert(source, gc.Equals, environs.ConfigFromEnvirons)
   111  	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
   112  }
   113  
   114  func (*OpenSuite) TestConfigForNameNoDefault(c *gc.C) {
   115  	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
   116  	cfg, source, err := environs.ConfigForName("", configstore.NewMem())
   117  	c.Assert(err, gc.ErrorMatches, "no default environment found")
   118  	c.Assert(cfg, gc.IsNil)
   119  	c.Assert(source, gc.Equals, environs.ConfigFromEnvirons)
   120  }
   121  
   122  func (*OpenSuite) TestConfigForNameDefault(c *gc.C) {
   123  	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
   124  	cfg, source, err := environs.ConfigForName("", configstore.NewMem())
   125  	c.Assert(err, gc.IsNil)
   126  	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
   127  	c.Assert(source, gc.Equals, environs.ConfigFromEnvirons)
   128  }
   129  
   130  func (*OpenSuite) TestConfigForNameFromInfo(c *gc.C) {
   131  	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
   132  	store := configstore.NewMem()
   133  	cfg, source, err := environs.ConfigForName("", store)
   134  	c.Assert(err, gc.IsNil)
   135  	c.Assert(source, gc.Equals, environs.ConfigFromEnvirons)
   136  
   137  	info, err := store.CreateInfo("test-config")
   138  	c.Assert(err, gc.IsNil)
   139  	var attrs testing.Attrs = cfg.AllAttrs()
   140  	attrs = attrs.Merge(testing.Attrs{
   141  		"name": "test-config",
   142  	})
   143  	info.SetBootstrapConfig(attrs)
   144  	err = info.Write()
   145  	c.Assert(err, gc.IsNil)
   146  
   147  	cfg, source, err = environs.ConfigForName("test-config", store)
   148  	c.Assert(err, gc.IsNil)
   149  	c.Assert(source, gc.Equals, environs.ConfigFromInfo)
   150  	c.Assert(testing.Attrs(cfg.AllAttrs()), gc.DeepEquals, attrs)
   151  }
   152  
   153  func (*OpenSuite) TestNew(c *gc.C) {
   154  	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
   155  		testing.Attrs{
   156  			"state-server": false,
   157  			"name":         "erewhemos",
   158  		},
   159  	))
   160  	c.Assert(err, gc.IsNil)
   161  	e, err := environs.New(cfg)
   162  	c.Assert(err, gc.ErrorMatches, "environment is not prepared")
   163  	c.Assert(e, gc.IsNil)
   164  }
   165  
   166  func (*OpenSuite) TestPrepare(c *gc.C) {
   167  	baselineAttrs := dummy.SampleConfig().Merge(testing.Attrs{
   168  		"state-server": false,
   169  		"name":         "erewhemos",
   170  	}).Delete(
   171  		"ca-cert",
   172  		"ca-private-key",
   173  		"admin-secret",
   174  	)
   175  	cfg, err := config.New(config.NoDefaults, baselineAttrs)
   176  	c.Assert(err, gc.IsNil)
   177  	store := configstore.NewMem()
   178  	env, err := environs.Prepare(cfg, store)
   179  	c.Assert(err, gc.IsNil)
   180  	// Check we can access storage ok, which implies the environment has been prepared.
   181  	c.Assert(env.Storage(), gc.NotNil)
   182  
   183  	// Check that the environment info file was correctly created.
   184  	info, err := store.ReadInfo("erewhemos")
   185  	c.Assert(err, gc.IsNil)
   186  	c.Assert(info.Initialized(), jc.IsTrue)
   187  	c.Assert(info.BootstrapConfig(), gc.DeepEquals, env.Config().AllAttrs())
   188  	c.Logf("bootstrap config: %#v", info.BootstrapConfig())
   189  
   190  	// Check that an admin-secret was chosen.
   191  	adminSecret := env.Config().AdminSecret()
   192  	c.Assert(adminSecret, gc.HasLen, 32)
   193  	c.Assert(adminSecret, gc.Matches, "^[0-9a-f]*$")
   194  
   195  	// Check that the CA cert was generated.
   196  	cfgCertPEM, cfgCertOK := env.Config().CACert()
   197  	cfgKeyPEM, cfgKeyOK := env.Config().CAPrivateKey()
   198  	c.Assert(cfgCertOK, gc.Equals, true)
   199  	c.Assert(cfgKeyOK, gc.Equals, true)
   200  
   201  	// Check the common name of the generated cert
   202  	caCert, _, err := cert.ParseCertAndKey(cfgCertPEM, cfgKeyPEM)
   203  	c.Assert(err, gc.IsNil)
   204  	c.Assert(caCert.Subject.CommonName, gc.Equals, `juju-generated CA for environment "`+testing.SampleEnvName+`"`)
   205  
   206  	// Check we can call Prepare again.
   207  	env, err = environs.Prepare(cfg, store)
   208  	c.Assert(err, gc.IsNil)
   209  	c.Assert(env.Name(), gc.Equals, "erewhemos")
   210  	c.Assert(env.Storage(), gc.NotNil)
   211  	c.Assert(env.Config().AllAttrs(), gc.DeepEquals, info.BootstrapConfig())
   212  }
   213  
   214  func (*OpenSuite) TestPrepareGeneratesDifferentAdminSecrets(c *gc.C) {
   215  	baselineAttrs := dummy.SampleConfig().Merge(testing.Attrs{
   216  		"state-server": false,
   217  		"name":         "erewhemos",
   218  	}).Delete(
   219  		"admin-secret",
   220  	)
   221  	cfg, err := config.New(config.NoDefaults, baselineAttrs)
   222  	c.Assert(err, gc.IsNil)
   223  
   224  	env0, err := environs.Prepare(cfg, configstore.NewMem())
   225  	c.Assert(err, gc.IsNil)
   226  	adminSecret0 := env0.Config().AdminSecret()
   227  	c.Assert(adminSecret0, gc.HasLen, 32)
   228  	c.Assert(adminSecret0, gc.Matches, "^[0-9a-f]*$")
   229  
   230  	env1, err := environs.Prepare(cfg, configstore.NewMem())
   231  	c.Assert(err, gc.IsNil)
   232  	adminSecret1 := env1.Config().AdminSecret()
   233  	c.Assert(adminSecret1, gc.HasLen, 32)
   234  	c.Assert(adminSecret1, gc.Matches, "^[0-9a-f]*$")
   235  
   236  	c.Assert(adminSecret1, gc.Not(gc.Equals), adminSecret0)
   237  }
   238  
   239  func (*OpenSuite) TestPrepareWithMissingKey(c *gc.C) {
   240  	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Delete("ca-cert", "ca-private-key").Merge(
   241  		testing.Attrs{
   242  			"state-server": false,
   243  			"name":         "erewhemos",
   244  			"ca-cert":      string(testing.CACert),
   245  		},
   246  	))
   247  	c.Assert(err, gc.IsNil)
   248  	env, err := environs.Prepare(cfg, configstore.NewMem())
   249  	c.Assert(err, gc.ErrorMatches, "cannot ensure CA certificate: environment configuration with a certificate but no CA private key")
   250  	c.Assert(env, gc.IsNil)
   251  }
   252  
   253  func (*OpenSuite) TestPrepareWithExistingKeyPair(c *gc.C) {
   254  	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
   255  		testing.Attrs{
   256  			"state-server":   false,
   257  			"name":           "erewhemos",
   258  			"ca-cert":        string(testing.CACert),
   259  			"ca-private-key": string(testing.CAKey),
   260  		},
   261  	))
   262  	c.Assert(err, gc.IsNil)
   263  	env, err := environs.Prepare(cfg, configstore.NewMem())
   264  	c.Assert(err, gc.IsNil)
   265  	cfgCertPEM, cfgCertOK := env.Config().CACert()
   266  	cfgKeyPEM, cfgKeyOK := env.Config().CAPrivateKey()
   267  	c.Assert(cfgCertOK, gc.Equals, true)
   268  	c.Assert(cfgKeyOK, gc.Equals, true)
   269  	c.Assert(string(cfgCertPEM), gc.DeepEquals, testing.CACert)
   270  	c.Assert(string(cfgKeyPEM), gc.DeepEquals, testing.CAKey)
   271  }
   272  
   273  func (*OpenSuite) TestDestroy(c *gc.C) {
   274  	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
   275  		testing.Attrs{
   276  			"state-server": false,
   277  			"name":         "erewhemos",
   278  		},
   279  	))
   280  	c.Assert(err, gc.IsNil)
   281  
   282  	store := configstore.NewMem()
   283  	// Prepare the environment and sanity-check that
   284  	// the config storage info has been made.
   285  	e, err := environs.Prepare(cfg, store)
   286  	c.Assert(err, gc.IsNil)
   287  	_, err = store.ReadInfo(e.Name())
   288  	c.Assert(err, gc.IsNil)
   289  
   290  	err = environs.Destroy(e, store)
   291  	c.Assert(err, gc.IsNil)
   292  
   293  	// Check that the environment has actually been destroyed
   294  	// and that the config info has been destroyed too.
   295  	_, _, err = e.StateInfo()
   296  	c.Assert(err, gc.ErrorMatches, "environment has been destroyed")
   297  	_, err = store.ReadInfo(e.Name())
   298  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   299  }
   300  
   301  func (*OpenSuite) TestNewFromAttrs(c *gc.C) {
   302  	e, err := environs.NewFromAttrs(dummy.SampleConfig().Merge(
   303  		testing.Attrs{
   304  			"state-server": false,
   305  			"name":         "erewhemos",
   306  		},
   307  	))
   308  	c.Assert(err, gc.ErrorMatches, "environment is not prepared")
   309  	c.Assert(e, gc.IsNil)
   310  }
   311  
   312  const checkEnv = `
   313  environments:
   314      test:
   315          type: dummy
   316          state-server: false
   317          authorized-keys: i-am-a-key
   318  `
   319  
   320  type checkEnvironmentSuite struct{}
   321  
   322  var _ = gc.Suite(&checkEnvironmentSuite{})
   323  
   324  func (s *checkEnvironmentSuite) TearDownTest(c *gc.C) {
   325  	dummy.Reset()
   326  }
   327  
   328  func (s *checkEnvironmentSuite) TestCheckEnvironment(c *gc.C) {
   329  	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()
   330  
   331  	environ, err := environs.PrepareFromName("test", configstore.NewMem())
   332  	c.Assert(err, gc.IsNil)
   333  
   334  	// VerifyStorage is sufficient for our tests and much simpler
   335  	// than Bootstrap which calls it.
   336  	stor := environ.Storage()
   337  	err = environs.VerifyStorage(stor)
   338  	c.Assert(err, gc.IsNil)
   339  	err = environs.CheckEnvironment(environ)
   340  	c.Assert(err, gc.IsNil)
   341  }
   342  
   343  func (s *checkEnvironmentSuite) TestCheckEnvironmentFileNotFound(c *gc.C) {
   344  	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()
   345  
   346  	environ, err := environs.PrepareFromName("test", configstore.NewMem())
   347  	c.Assert(err, gc.IsNil)
   348  
   349  	// VerifyStorage is sufficient for our tests and much simpler
   350  	// than Bootstrap which calls it.
   351  	stor := environ.Storage()
   352  	err = environs.VerifyStorage(stor)
   353  	c.Assert(err, gc.IsNil)
   354  
   355  	// When the bootstrap-verify file does not exist, it still believes
   356  	// the environment is a juju-core one because earlier versions
   357  	// did not create that file.
   358  	err = stor.Remove(environs.VerificationFilename)
   359  	c.Assert(err, gc.IsNil)
   360  	err = environs.CheckEnvironment(environ)
   361  	c.Assert(err, gc.IsNil)
   362  }
   363  
   364  func (s *checkEnvironmentSuite) TestCheckEnvironmentGetFails(c *gc.C) {
   365  	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()
   366  
   367  	environ, err := environs.PrepareFromName("test", configstore.NewMem())
   368  	c.Assert(err, gc.IsNil)
   369  
   370  	// VerifyStorage is sufficient for our tests and much simpler
   371  	// than Bootstrap which calls it.
   372  	stor := environ.Storage()
   373  	err = environs.VerifyStorage(stor)
   374  	c.Assert(err, gc.IsNil)
   375  
   376  	// When fetching the verification file from storage fails,
   377  	// we get an InvalidEnvironmentError.
   378  	someError := errors.Unauthorizedf("you shall not pass")
   379  	dummy.Poison(stor, environs.VerificationFilename, someError)
   380  	err = environs.CheckEnvironment(environ)
   381  	c.Assert(err, gc.Equals, someError)
   382  }
   383  
   384  func (s *checkEnvironmentSuite) TestCheckEnvironmentBadContent(c *gc.C) {
   385  	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()
   386  
   387  	environ, err := environs.PrepareFromName("test", configstore.NewMem())
   388  	c.Assert(err, gc.IsNil)
   389  
   390  	// We mock a bad (eg. from a Python-juju environment) bootstrap-verify.
   391  	stor := environ.Storage()
   392  	content := "bad verification content"
   393  	reader := strings.NewReader(content)
   394  	err = stor.Put(environs.VerificationFilename, reader, int64(len(content)))
   395  	c.Assert(err, gc.IsNil)
   396  
   397  	// When the bootstrap-verify file contains unexpected content,
   398  	// we get an InvalidEnvironmentError.
   399  	err = environs.CheckEnvironment(environ)
   400  	c.Assert(err, gc.Equals, environs.InvalidEnvironmentError)
   401  }