github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/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 }