github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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 ctx := testing.Context(c) 41 env, err := environs.Prepare(cfg, ctx, configstore.NewMem()) 42 c.Assert(err, gc.IsNil) 43 envtesting.UploadFakeTools(c, env.Storage()) 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 ctx := testing.Context(c) 61 e, err := environs.PrepareFromName("erewhemos", ctx, store) 62 c.Assert(err, gc.IsNil) 63 64 e, err = environs.NewFromName("erewhemos", store) 65 c.Assert(err, gc.IsNil) 66 c.Assert(e.Name(), gc.Equals, "erewhemos") 67 } 68 69 func (*OpenSuite) TestNewFromNameWithInvalidInfo(c *gc.C) { 70 defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore() 71 store := configstore.NewMem() 72 cfg, _, err := environs.ConfigForName("erewhemos", store) 73 c.Assert(err, gc.IsNil) 74 info, err := store.CreateInfo("erewhemos") 75 c.Assert(err, gc.IsNil) 76 77 // The configuration from environments.yaml is invalid 78 // because it doesn't contain the state-id attribute which 79 // the dummy environment adds at Prepare time. 80 info.SetBootstrapConfig(cfg.AllAttrs()) 81 err = info.Write() 82 c.Assert(err, gc.IsNil) 83 84 e, err := environs.NewFromName("erewhemos", store) 85 c.Assert(err, gc.ErrorMatches, "environment is not prepared") 86 c.Assert(e, gc.IsNil) 87 } 88 89 func (*OpenSuite) TestNewFromNameWithInvalidEnvironConfig(c *gc.C) { 90 defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore() 91 store := configstore.NewMem() 92 93 e, err := environs.NewFromName("erewhemos", store) 94 c.Assert(err, gc.Equals, environs.ErrNotBootstrapped) 95 c.Assert(e, gc.IsNil) 96 } 97 98 func (*OpenSuite) TestPrepareFromName(c *gc.C) { 99 defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore() 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 defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore() 110 cfg, source, err := environs.ConfigForName("erewhemos", configstore.NewMem()) 111 c.Assert(err, gc.IsNil) 112 c.Assert(source, gc.Equals, environs.ConfigFromEnvirons) 113 c.Assert(cfg.Name(), gc.Equals, "erewhemos") 114 } 115 116 func (*OpenSuite) TestConfigForNameNoDefault(c *gc.C) { 117 defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore() 118 cfg, source, err := environs.ConfigForName("", configstore.NewMem()) 119 c.Assert(err, gc.ErrorMatches, "no default environment found") 120 c.Assert(cfg, gc.IsNil) 121 c.Assert(source, gc.Equals, environs.ConfigFromEnvirons) 122 } 123 124 func (*OpenSuite) TestConfigForNameDefault(c *gc.C) { 125 defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore() 126 cfg, source, err := environs.ConfigForName("", configstore.NewMem()) 127 c.Assert(err, gc.IsNil) 128 c.Assert(cfg.Name(), gc.Equals, "erewhemos") 129 c.Assert(source, gc.Equals, environs.ConfigFromEnvirons) 130 } 131 132 func (*OpenSuite) TestConfigForNameFromInfo(c *gc.C) { 133 defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore() 134 store := configstore.NewMem() 135 cfg, source, err := environs.ConfigForName("", store) 136 c.Assert(err, gc.IsNil) 137 c.Assert(source, gc.Equals, environs.ConfigFromEnvirons) 138 139 info, err := store.CreateInfo("test-config") 140 c.Assert(err, gc.IsNil) 141 var attrs testing.Attrs = cfg.AllAttrs() 142 attrs = attrs.Merge(testing.Attrs{ 143 "name": "test-config", 144 }) 145 info.SetBootstrapConfig(attrs) 146 err = info.Write() 147 c.Assert(err, gc.IsNil) 148 149 cfg, source, err = environs.ConfigForName("test-config", store) 150 c.Assert(err, gc.IsNil) 151 c.Assert(source, gc.Equals, environs.ConfigFromInfo) 152 c.Assert(testing.Attrs(cfg.AllAttrs()), gc.DeepEquals, attrs) 153 } 154 155 func (*OpenSuite) TestNew(c *gc.C) { 156 cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge( 157 testing.Attrs{ 158 "state-server": false, 159 "name": "erewhemos", 160 }, 161 )) 162 c.Assert(err, gc.IsNil) 163 e, err := environs.New(cfg) 164 c.Assert(err, gc.ErrorMatches, "environment is not prepared") 165 c.Assert(e, gc.IsNil) 166 } 167 168 func (*OpenSuite) TestPrepare(c *gc.C) { 169 baselineAttrs := dummy.SampleConfig().Merge(testing.Attrs{ 170 "state-server": false, 171 "name": "erewhemos", 172 }).Delete( 173 "ca-cert", 174 "ca-private-key", 175 "admin-secret", 176 ) 177 cfg, err := config.New(config.NoDefaults, baselineAttrs) 178 c.Assert(err, gc.IsNil) 179 store := configstore.NewMem() 180 ctx := testing.Context(c) 181 env, err := environs.Prepare(cfg, ctx, store) 182 c.Assert(err, gc.IsNil) 183 // Check we can access storage ok, which implies the environment has been prepared. 184 c.Assert(env.Storage(), gc.NotNil) 185 186 // Check that the environment info file was correctly created. 187 info, err := store.ReadInfo("erewhemos") 188 c.Assert(err, gc.IsNil) 189 c.Assert(info.Initialized(), jc.IsTrue) 190 c.Assert(info.BootstrapConfig(), gc.DeepEquals, env.Config().AllAttrs()) 191 c.Logf("bootstrap config: %#v", info.BootstrapConfig()) 192 193 // Check that an admin-secret was chosen. 194 adminSecret := env.Config().AdminSecret() 195 c.Assert(adminSecret, gc.HasLen, 32) 196 c.Assert(adminSecret, gc.Matches, "^[0-9a-f]*$") 197 198 // Check that the CA cert was generated. 199 cfgCertPEM, cfgCertOK := env.Config().CACert() 200 cfgKeyPEM, cfgKeyOK := env.Config().CAPrivateKey() 201 c.Assert(cfgCertOK, gc.Equals, true) 202 c.Assert(cfgKeyOK, gc.Equals, true) 203 204 // Check the common name of the generated cert 205 caCert, _, err := cert.ParseCertAndKey(cfgCertPEM, cfgKeyPEM) 206 c.Assert(err, gc.IsNil) 207 c.Assert(caCert.Subject.CommonName, gc.Equals, `juju-generated CA for environment "`+testing.SampleEnvName+`"`) 208 209 // Check we can call Prepare again. 210 env, err = environs.Prepare(cfg, ctx, store) 211 c.Assert(err, gc.IsNil) 212 c.Assert(env.Name(), gc.Equals, "erewhemos") 213 c.Assert(env.Storage(), gc.NotNil) 214 c.Assert(env.Config().AllAttrs(), gc.DeepEquals, info.BootstrapConfig()) 215 } 216 217 func (*OpenSuite) TestPrepareGeneratesDifferentAdminSecrets(c *gc.C) { 218 baselineAttrs := dummy.SampleConfig().Merge(testing.Attrs{ 219 "state-server": false, 220 "name": "erewhemos", 221 }).Delete( 222 "admin-secret", 223 ) 224 cfg, err := config.New(config.NoDefaults, baselineAttrs) 225 c.Assert(err, gc.IsNil) 226 227 ctx := testing.Context(c) 228 env0, err := environs.Prepare(cfg, ctx, configstore.NewMem()) 229 c.Assert(err, gc.IsNil) 230 adminSecret0 := env0.Config().AdminSecret() 231 c.Assert(adminSecret0, gc.HasLen, 32) 232 c.Assert(adminSecret0, gc.Matches, "^[0-9a-f]*$") 233 234 env1, err := environs.Prepare(cfg, ctx, configstore.NewMem()) 235 c.Assert(err, gc.IsNil) 236 adminSecret1 := env1.Config().AdminSecret() 237 c.Assert(adminSecret1, gc.HasLen, 32) 238 c.Assert(adminSecret1, gc.Matches, "^[0-9a-f]*$") 239 240 c.Assert(adminSecret1, gc.Not(gc.Equals), adminSecret0) 241 } 242 243 func (*OpenSuite) TestPrepareWithMissingKey(c *gc.C) { 244 cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Delete("ca-cert", "ca-private-key").Merge( 245 testing.Attrs{ 246 "state-server": false, 247 "name": "erewhemos", 248 "ca-cert": string(testing.CACert), 249 }, 250 )) 251 c.Assert(err, gc.IsNil) 252 store := configstore.NewMem() 253 env, err := environs.Prepare(cfg, testing.Context(c), store) 254 c.Assert(err, gc.ErrorMatches, "cannot ensure CA certificate: environment configuration with a certificate but no CA private key") 255 c.Assert(env, gc.IsNil) 256 // Ensure that the config storage info is cleaned up. 257 _, err = store.ReadInfo(cfg.Name()) 258 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 259 } 260 261 func (*OpenSuite) TestPrepareWithExistingKeyPair(c *gc.C) { 262 cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge( 263 testing.Attrs{ 264 "state-server": false, 265 "name": "erewhemos", 266 "ca-cert": string(testing.CACert), 267 "ca-private-key": string(testing.CAKey), 268 }, 269 )) 270 c.Assert(err, gc.IsNil) 271 ctx := testing.Context(c) 272 env, err := environs.Prepare(cfg, ctx, configstore.NewMem()) 273 c.Assert(err, gc.IsNil) 274 cfgCertPEM, cfgCertOK := env.Config().CACert() 275 cfgKeyPEM, cfgKeyOK := env.Config().CAPrivateKey() 276 c.Assert(cfgCertOK, gc.Equals, true) 277 c.Assert(cfgKeyOK, gc.Equals, true) 278 c.Assert(string(cfgCertPEM), gc.DeepEquals, testing.CACert) 279 c.Assert(string(cfgKeyPEM), gc.DeepEquals, testing.CAKey) 280 } 281 282 func (*OpenSuite) TestDestroy(c *gc.C) { 283 cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge( 284 testing.Attrs{ 285 "state-server": false, 286 "name": "erewhemos", 287 }, 288 )) 289 c.Assert(err, gc.IsNil) 290 291 store := configstore.NewMem() 292 // Prepare the environment and sanity-check that 293 // the config storage info has been made. 294 ctx := testing.Context(c) 295 e, err := environs.Prepare(cfg, ctx, store) 296 c.Assert(err, gc.IsNil) 297 _, err = store.ReadInfo(e.Name()) 298 c.Assert(err, gc.IsNil) 299 300 err = environs.Destroy(e, store) 301 c.Assert(err, gc.IsNil) 302 303 // Check that the environment has actually been destroyed 304 // and that the config info has been destroyed too. 305 _, _, err = e.StateInfo() 306 c.Assert(err, gc.ErrorMatches, "environment has been destroyed") 307 _, err = store.ReadInfo(e.Name()) 308 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 309 } 310 311 func (*OpenSuite) TestNewFromAttrs(c *gc.C) { 312 e, err := environs.NewFromAttrs(dummy.SampleConfig().Merge( 313 testing.Attrs{ 314 "state-server": false, 315 "name": "erewhemos", 316 }, 317 )) 318 c.Assert(err, gc.ErrorMatches, "environment is not prepared") 319 c.Assert(e, gc.IsNil) 320 } 321 322 const checkEnv = ` 323 environments: 324 test: 325 type: dummy 326 state-server: false 327 authorized-keys: i-am-a-key 328 ` 329 330 type checkEnvironmentSuite struct{} 331 332 var _ = gc.Suite(&checkEnvironmentSuite{}) 333 334 func (s *checkEnvironmentSuite) TearDownTest(c *gc.C) { 335 dummy.Reset() 336 } 337 338 func (s *checkEnvironmentSuite) TestCheckEnvironment(c *gc.C) { 339 defer testing.MakeFakeHome(c, checkEnv, "existing").Restore() 340 341 ctx := testing.Context(c) 342 environ, err := environs.PrepareFromName("test", ctx, configstore.NewMem()) 343 c.Assert(err, gc.IsNil) 344 345 // VerifyStorage is sufficient for our tests and much simpler 346 // than Bootstrap which calls it. 347 stor := environ.Storage() 348 err = environs.VerifyStorage(stor) 349 c.Assert(err, gc.IsNil) 350 err = environs.CheckEnvironment(environ) 351 c.Assert(err, gc.IsNil) 352 } 353 354 func (s *checkEnvironmentSuite) TestCheckEnvironmentFileNotFound(c *gc.C) { 355 defer testing.MakeFakeHome(c, checkEnv, "existing").Restore() 356 357 ctx := testing.Context(c) 358 environ, err := environs.PrepareFromName("test", ctx, configstore.NewMem()) 359 c.Assert(err, gc.IsNil) 360 361 // VerifyStorage is sufficient for our tests and much simpler 362 // than Bootstrap which calls it. 363 stor := environ.Storage() 364 err = environs.VerifyStorage(stor) 365 c.Assert(err, gc.IsNil) 366 367 // When the bootstrap-verify file does not exist, it still believes 368 // the environment is a juju-core one because earlier versions 369 // did not create that file. 370 err = stor.Remove(environs.VerificationFilename) 371 c.Assert(err, gc.IsNil) 372 err = environs.CheckEnvironment(environ) 373 c.Assert(err, gc.IsNil) 374 } 375 376 func (s *checkEnvironmentSuite) TestCheckEnvironmentGetFails(c *gc.C) { 377 defer testing.MakeFakeHome(c, checkEnv, "existing").Restore() 378 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 defer testing.MakeFakeHome(c, checkEnv, "existing").Restore() 399 400 ctx := testing.Context(c) 401 environ, err := environs.PrepareFromName("test", ctx, configstore.NewMem()) 402 c.Assert(err, gc.IsNil) 403 404 // We mock a bad (eg. from a Python-juju environment) bootstrap-verify. 405 stor := environ.Storage() 406 content := "bad verification content" 407 reader := strings.NewReader(content) 408 err = stor.Put(environs.VerificationFilename, reader, int64(len(content))) 409 c.Assert(err, gc.IsNil) 410 411 // When the bootstrap-verify file contains unexpected content, 412 // we get an InvalidEnvironmentError. 413 err = environs.CheckEnvironment(environ) 414 c.Assert(err, gc.Equals, environs.InvalidEnvironmentError) 415 }