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