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 }