func (s *InitializeSuite) TestDoubleInitializeConfig(c *gc.C) { cfg := testing.EnvironConfig(c) owner := names.NewLocalUserTag("initialize-admin") mgoInfo := statetesting.NewMongoInfo() dialOpts := statetesting.NewDialOpts() st, err := state.Initialize(owner, mgoInfo, cfg, dialOpts, state.Policy(nil)) c.Assert(err, jc.ErrorIsNil) st.Close() _, err = state.Initialize(owner, mgoInfo, cfg, dialOpts, state.Policy(nil)) c.Assert(err, gc.ErrorMatches, "already initialized") }
func (s *InitializeSuite) testBadModelConfig(c *gc.C, update map[string]interface{}, remove []string, expect string) { good := testing.CustomModelConfig(c, testing.Attrs{"uuid": testing.ModelTag.Id()}) bad, err := good.Apply(update) c.Assert(err, jc.ErrorIsNil) bad, err = bad.Remove(remove) c.Assert(err, jc.ErrorIsNil) owner := names.NewLocalUserTag("initialize-admin") controllerCfg := testing.FakeControllerConfig() args := state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", CloudRegion: "dummy-region", Owner: owner, Config: bad, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, Regions: []cloud.Region{{Name: "dummy-region"}}, }, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), } _, err = state.Initialize(args) c.Assert(err, gc.ErrorMatches, expect) args.ControllerModelArgs.Config = good st, err := state.Initialize(args) c.Assert(err, jc.ErrorIsNil) st.Close() s.openState(c, st.ModelTag()) err = s.State.UpdateModelConfig(update, remove, nil) c.Assert(err, gc.ErrorMatches, expect) // ModelConfig remains inviolate. cfg, err := s.State.ModelConfig() c.Assert(err, jc.ErrorIsNil) goodWithDefaults, err := config.New(config.UseDefaults, good.AllAttrs()) c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.AllAttrs(), jc.DeepEquals, goodWithDefaults.AllAttrs()) }
func (s *InitializeSuite) TestInitializeWithInvalidCredentialType(c *gc.C) { owner := names.NewLocalUserTag("initialize-admin") modelCfg := testing.ModelConfig(c) controllerCfg := testing.FakeControllerConfig() credentialTag := names.NewCloudCredentialTag("dummy/" + owner.Canonical() + "/borken") _, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: owner, Config: modelCfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{ cloud.AccessKeyAuthType, cloud.OAuth1AuthType, }, }, CloudCredentials: map[names.CloudCredentialTag]cloud.Credential{ credentialTag: cloud.NewCredential(cloud.UserPassAuthType, nil), }, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, gc.ErrorMatches, `validating initialization args: validating cloud credentials: credential "dummy/initialize-admin@local/borken" with auth-type "userpass" is not supported \(expected one of \["access-key" "oauth1"\]\)`, ) }
func (s *InitializeSuite) TestInitialize(c *gc.C) { cfg := testing.EnvironConfig(c) initial := cfg.AllAttrs() st, err := state.Initialize(state.TestingStateInfo(), cfg, state.TestingDialOpts(), state.Policy(nil)) c.Assert(err, gc.IsNil) c.Assert(st, gc.NotNil) err = st.Close() c.Assert(err, gc.IsNil) s.openState(c) cfg, err = s.State.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, initial) env, err := s.State.Environment() c.Assert(err, gc.IsNil) entity, err := s.State.FindEntity("environment-" + env.UUID()) c.Assert(err, gc.IsNil) annotator := entity.(state.Annotator) annotations, err := annotator.Annotations() c.Assert(err, gc.IsNil) c.Assert(annotations, gc.HasLen, 0) cons, err := s.State.EnvironConstraints() c.Assert(err, gc.IsNil) c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) addrs, err := s.State.APIHostPorts() c.Assert(err, gc.IsNil) c.Assert(addrs, gc.HasLen, 0) info, err := s.State.StateServerInfo() c.Assert(err, gc.IsNil) c.Assert(info, jc.DeepEquals, &state.StateServerInfo{}) }
func (s *InitializeSuite) TestEnvironConfigWithoutAgentVersion(c *gc.C) { // admin-secret blocks Initialize. good := testing.EnvironConfig(c) attrs := good.AllAttrs() delete(attrs, "agent-version") bad, err := config.New(config.NoDefaults, attrs) c.Assert(err, jc.ErrorIsNil) owner := names.NewLocalUserTag("initialize-admin") _, err = state.Initialize(owner, statetesting.NewMongoInfo(), bad, statetesting.NewDialOpts(), state.Policy(nil)) c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state") st := statetesting.Initialize(c, owner, good, nil) // yay side effects st.Close() s.openState(c, st.EnvironTag()) err = s.State.UpdateEnvironConfig(map[string]interface{}{}, []string{"agent-version"}, nil) c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state") // EnvironConfig remains inviolate. cfg, err := s.State.EnvironConfig() c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, good.AllAttrs()) }
// InitializeState should be called on the bootstrap machine's agent // configuration. It uses that information to create the state server, dial the // state server, and initialize it. It also generates a new password for the // bootstrap machine and calls Write to save the the configuration. // // The envCfg values will be stored in the state's EnvironConfig; the // machineCfg values will be used to configure the bootstrap Machine, // and its constraints will be also be used for the environment-level // constraints. The connection to the state server will respect the // given timeout parameter. // // InitializeState returns the newly initialized state and bootstrap // machine. If it fails, the state may well be irredeemably compromised. func InitializeState(adminUser names.UserTag, c ConfigSetter, envCfg *config.Config, machineCfg BootstrapMachineConfig, dialOpts mongo.DialOpts, policy state.Policy) (_ *state.State, _ *state.Machine, resultErr error) { if c.Tag() != names.NewMachineTag(BootstrapMachineId) { return nil, nil, errors.Errorf("InitializeState not called with bootstrap machine's configuration") } servingInfo, ok := c.StateServingInfo() if !ok { return nil, nil, errors.Errorf("state serving information not available") } // N.B. no users are set up when we're initializing the state, // so don't use any tag or password when opening it. info, ok := c.MongoInfo() if !ok { return nil, nil, errors.Errorf("stateinfo not available") } info.Tag = nil info.Password = c.OldPassword() if err := initMongoAdminUser(info.Info, dialOpts, info.Password); err != nil { return nil, nil, errors.Annotate(err, "failed to initialize mongo admin user") } logger.Debugf("initializing address %v", info.Addrs) st, err := state.Initialize(adminUser, info, envCfg, dialOpts, policy) if err != nil { return nil, nil, errors.Errorf("failed to initialize state: %v", err) } logger.Debugf("connected to initial state") defer func() { if resultErr != nil { st.Close() } }() servingInfo.SharedSecret = machineCfg.SharedSecret c.SetStateServingInfo(servingInfo) // Filter out any LXC bridge addresses from the machine addresses, // except for local environments. See LP bug #1416928. if !isLocalEnv(envCfg) { machineCfg.Addresses = network.FilterLXCAddresses(machineCfg.Addresses) } else { logger.Debugf("local environment - not filtering addresses from %v", machineCfg.Addresses) } if err = initAPIHostPorts(c, st, machineCfg.Addresses, servingInfo.APIPort); err != nil { return nil, nil, err } ssi := paramsStateServingInfoToStateStateServingInfo(servingInfo) if err := st.SetStateServingInfo(ssi); err != nil { return nil, nil, errors.Errorf("cannot set state serving info: %v", err) } m, err := initConstraintsAndBootstrapMachine(c, st, machineCfg) if err != nil { return nil, nil, err } return st, m, nil }
func (s *InitializeSuite) TestInitializeWithCloudRegionConfig(c *gc.C) { cfg := testing.ModelConfig(c) uuid := cfg.UUID() // Phony region-config regionInheritedConfigIn := cloud.RegionConfig{ "a-region": cloud.Attrs{ "a-key": "a-value", }, "b-region": cloud.Attrs{ "b-key": "b-value", }, } owner := names.NewLocalUserTag("initialize-admin") controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: owner, Config: cfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, RegionConfig: regionInheritedConfigIn, // Init with phony region-config }, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.NotNil) modelTag := st.ModelTag() c.Assert(modelTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, jc.ErrorIsNil) s.openState(c, modelTag) for k := range regionInheritedConfigIn { // Query for config for each region regionInheritedConfig, err := state.ReadSettings( s.State, state.GlobalSettingsC, "dummy#"+k) c.Assert(err, jc.ErrorIsNil) c.Assert( cloud.Attrs(regionInheritedConfig.Map()), jc.DeepEquals, regionInheritedConfigIn[k]) } }
func (s *InitializeSuite) TestInitializeWithCloudRegionHits(c *gc.C) { cfg := testing.ModelConfig(c) uuid := cfg.UUID() controllerInheritedConfigIn := map[string]interface{}{ "no-proxy": "local", } // Phony region-config regionInheritedConfigIn := cloud.RegionConfig{ "a-region": cloud.Attrs{ "no-proxy": "a-value", }, "b-region": cloud.Attrs{ "no-proxy": "b-value", }, } owner := names.NewLocalUserTag("initialize-admin") controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: owner, Config: cfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, RegionConfig: regionInheritedConfigIn, // Init with phony region-config }, ControllerInheritedConfig: controllerInheritedConfigIn, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.NotNil) modelTag := st.ModelTag() c.Assert(modelTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, jc.ErrorIsNil) s.openState(c, modelTag) var attrs map[string]interface{} for r := range regionInheritedConfigIn { rspec := &environs.RegionSpec{Cloud: "dummy", Region: r} got, err := s.State.ComposeNewModelConfig(attrs, rspec) c.Check(err, jc.ErrorIsNil) c.Assert(got["no-proxy"], gc.Equals, regionInheritedConfigIn[r]["no-proxy"]) } }
// Initialize initializes the state and returns it. If state was not // already initialized, and cfg is nil, the minimal default model // configuration will be used. func Initialize(c *gc.C, owner names.UserTag, cfg *config.Config, policy state.Policy) *state.State { if cfg == nil { cfg = testing.ModelConfig(c) } mgoInfo := NewMongoInfo() dialOpts := NewDialOpts() st, err := state.Initialize(owner, mgoInfo, cfg, dialOpts, policy) c.Assert(err, jc.ErrorIsNil) return st }
func (s *InitializeSuite) TestInitializeWithControllerInheritedConfig(c *gc.C) { cfg := testing.ModelConfig(c) uuid := cfg.UUID() initial := cfg.AllAttrs() controllerInheritedConfigIn := map[string]interface{}{ "default-series": initial["default-series"], } owner := names.NewLocalUserTag("initialize-admin") controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: owner, Config: cfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, }, ControllerInheritedConfig: controllerInheritedConfigIn, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.NotNil) modelTag := st.ModelTag() c.Assert(modelTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, jc.ErrorIsNil) s.openState(c, modelTag) controllerInheritedConfig, err := state.ReadSettings(s.State, state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey) c.Assert(err, jc.ErrorIsNil) c.Assert(controllerInheritedConfig.Map(), jc.DeepEquals, controllerInheritedConfigIn) expected := cfg.AllAttrs() for k, v := range config.ConfigDefaults() { if _, ok := expected[k]; !ok { expected[k] = v } } // Config as read from state has resources tags coerced to a map. expected["resource-tags"] = map[string]string{} cfg, err = s.State.ModelConfig() c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected) }
func (s *InitializeSuite) TestInitialize(c *gc.C) { cfg := testing.EnvironConfig(c) uuid, _ := cfg.UUID() initial := cfg.AllAttrs() st, err := state.Initialize(state.TestingMongoInfo(), cfg, state.TestingDialOpts(), nil) c.Assert(err, gc.IsNil) c.Assert(st, gc.NotNil) envTag := st.EnvironTag() c.Assert(envTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, gc.IsNil) s.openState(c) cfg, err = s.State.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, initial) // Check that the environment has been created. env, err := s.State.Environment() c.Assert(err, gc.IsNil) c.Assert(env.Tag(), gc.Equals, envTag) // Check that the owner has been created. owner := names.NewLocalUserTag("admin") c.Assert(env.Owner(), gc.Equals, owner) // Check that the owner can be retrieved by the tag. entity, err := s.State.FindEntity(env.Owner()) c.Assert(err, gc.IsNil) c.Assert(entity.Tag(), gc.Equals, owner) // Check that the owner has an EnvUser created for the bootstrapped environment. envUser, err := s.State.EnvironmentUser(env.Owner()) c.Assert(err, gc.IsNil) c.Assert(envUser.UserTag().Username(), gc.Equals, env.Owner().Username()) c.Assert(envUser.EnvironmentTag(), gc.Equals, env.Tag()) // Check that the environment can be found through the tag. entity, err = s.State.FindEntity(envTag) c.Assert(err, gc.IsNil) annotator := entity.(state.Annotator) annotations, err := annotator.Annotations() c.Assert(err, gc.IsNil) c.Assert(annotations, gc.HasLen, 0) cons, err := s.State.EnvironConstraints() c.Assert(err, gc.IsNil) c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) addrs, err := s.State.APIHostPorts() c.Assert(err, gc.IsNil) c.Assert(addrs, gc.HasLen, 0) info, err := s.State.StateServerInfo() c.Assert(err, gc.IsNil) c.Assert(info, jc.DeepEquals, &state.StateServerInfo{EnvironmentTag: envTag}) }
// InitializeWithArgs initializes the state and returns it. If state was not // already initialized, and args.Config is nil, the minimal default model // configuration will be used. func InitializeWithArgs(c *gc.C, args InitializeArgs) *state.State { if args.InitialConfig == nil { args.InitialConfig = testing.ModelConfig(c) } mgoInfo := NewMongoInfo() dialOpts := mongotest.DialOpts() controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: args.Clock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", CloudRegion: "dummy-region", Config: args.InitialConfig, Owner: args.Owner, StorageProviderRegistry: StorageProviders(), }, ControllerInheritedConfig: args.ControllerInheritedConfig, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, Regions: []cloud.Region{ cloud.Region{ Name: "dummy-region", Endpoint: "dummy-endpoint", IdentityEndpoint: "dummy-identity-endpoint", StorageEndpoint: "dummy-storage-endpoint", }, cloud.Region{ Name: "nether-region", Endpoint: "nether-endpoint", IdentityEndpoint: "nether-identity-endpoint", StorageEndpoint: "nether-storage-endpoint", }, cloud.Region{ Name: "unused-region", Endpoint: "unused-endpoint", IdentityEndpoint: "unused-identity-endpoint", StorageEndpoint: "unused-storage-endpoint", }, }, RegionConfig: args.RegionConfig, }, MongoInfo: mgoInfo, MongoDialOpts: dialOpts, NewPolicy: args.NewPolicy, }) c.Assert(err, jc.ErrorIsNil) return st }
func (s *InitializeSuite) TestDoubleInitializeConfig(c *gc.C) { cfg := testing.ModelConfig(c) owner := names.NewLocalUserTag("initialize-admin") mgoInfo := statetesting.NewMongoInfo() dialOpts := mongotest.DialOpts() controllerCfg := testing.FakeControllerConfig() args := state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: owner, Config: cfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, }, MongoInfo: mgoInfo, MongoDialOpts: dialOpts, } st, err := state.Initialize(args) c.Assert(err, jc.ErrorIsNil) err = st.Close() c.Check(err, jc.ErrorIsNil) st, err = state.Initialize(args) c.Check(err, gc.ErrorMatches, "already initialized") if !c.Check(st, gc.IsNil) { err = st.Close() c.Check(err, jc.ErrorIsNil) } }
func (s *InitializeSuite) TestInitialize(c *gc.C) { cfg := testing.ModelConfig(c) uuid, _ := cfg.UUID() initial := cfg.AllAttrs() owner := names.NewLocalUserTag("initialize-admin") st, err := state.Initialize(owner, statetesting.NewMongoInfo(), cfg, statetesting.NewDialOpts(), nil) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.NotNil) modelTag := st.ModelTag() c.Assert(modelTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, jc.ErrorIsNil) s.openState(c, modelTag) cfg, err = s.State.ModelConfig() c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, initial) // Check that the model has been created. env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Tag(), gc.Equals, modelTag) // Check that the owner has been created. c.Assert(env.Owner(), gc.Equals, owner) // Check that the owner can be retrieved by the tag. entity, err := s.State.FindEntity(env.Owner()) c.Assert(err, jc.ErrorIsNil) c.Assert(entity.Tag(), gc.Equals, owner) // Check that the owner has an ModelUser created for the bootstrapped model. modelUser, err := s.State.ModelUser(env.Owner()) c.Assert(err, jc.ErrorIsNil) c.Assert(modelUser.UserTag(), gc.Equals, owner) c.Assert(modelUser.ModelTag(), gc.Equals, env.Tag()) // Check that the model can be found through the tag. entity, err = s.State.FindEntity(modelTag) c.Assert(err, jc.ErrorIsNil) cons, err := s.State.ModelConstraints() c.Assert(err, jc.ErrorIsNil) c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) addrs, err := s.State.APIHostPorts() c.Assert(err, jc.ErrorIsNil) c.Assert(addrs, gc.HasLen, 0) info, err := s.State.StateServerInfo() c.Assert(err, jc.ErrorIsNil) c.Assert(info, jc.DeepEquals, &state.StateServerInfo{ModelTag: modelTag}) }
func InitializeState(c ConfigSetter, envCfg *config.Config, machineCfg BootstrapMachineConfig, dialOpts mongo.DialOpts, policy state.Policy) (_ *state.State, _ *state.Machine, resultErr error) { if c.Tag() != names.NewMachineTag(BootstrapMachineId) { return nil, nil, fmt.Errorf("InitializeState not called with bootstrap machine's configuration") } servingInfo, ok := c.StateServingInfo() if !ok { return nil, nil, fmt.Errorf("state serving information not available") } // N.B. no users are set up when we're initializing the state, // so don't use any tag or password when opening it. info, ok := c.MongoInfo() if !ok { return nil, nil, fmt.Errorf("stateinfo not available") } info.Tag = nil info.Password = c.OldPassword() if err := initMongoAdminUser(info.Info, dialOpts, info.Password); err != nil { return nil, nil, errors.Annotate(err, "failed to initialize mongo admin user") } logger.Debugf("initializing address %v", info.Addrs) st, err := state.Initialize(info, envCfg, dialOpts, policy) if err != nil { return nil, nil, fmt.Errorf("failed to initialize state: %v", err) } logger.Debugf("connected to initial state") defer func() { if resultErr != nil { st.Close() } }() servingInfo.SharedSecret = machineCfg.SharedSecret c.SetStateServingInfo(servingInfo) if err = initAPIHostPorts(c, st, machineCfg.Addresses, servingInfo.APIPort); err != nil { return nil, nil, err } if err := st.SetStateServingInfo(servingInfo); err != nil { return nil, nil, fmt.Errorf("cannot set state serving info: %v", err) } m, err := initUsersAndBootstrapMachine(c, st, machineCfg) if err != nil { return nil, nil, err } return st, m, nil }
// Initialize initializes the state and returns it. If state was not // already initialized, and cfg is nil, the minimal default model // configuration will be used. func Initialize(c *gc.C, owner names.UserTag, cfg *config.Config, controllerInheritedConfig map[string]interface{}, regionConfig cloud.RegionConfig, newPolicy state.NewPolicyFunc) *state.State { if cfg == nil { cfg = testing.ModelConfig(c) } mgoInfo := NewMongoInfo() dialOpts := mongotest.DialOpts() controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", CloudRegion: "dummy-region", Config: cfg, Owner: owner, StorageProviderRegistry: StorageProviders(), }, ControllerInheritedConfig: controllerInheritedConfig, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, Regions: []cloud.Region{ cloud.Region{ Name: "dummy-region", Endpoint: "dummy-endpoint", IdentityEndpoint: "dummy-identity-endpoint", StorageEndpoint: "dummy-storage-endpoint", }, cloud.Region{ Name: "nether-region", Endpoint: "nether-endpoint", IdentityEndpoint: "nether-identity-endpoint", StorageEndpoint: "nether-storage-endpoint", }, }, RegionConfig: regionConfig, }, MongoInfo: mgoInfo, MongoDialOpts: dialOpts, NewPolicy: newPolicy, }) c.Assert(err, jc.ErrorIsNil) return st }
func (s *ModelCloudValidationSuite) initializeState( c *gc.C, regions []cloud.Region, authTypes []cloud.AuthType, credentials map[names.CloudCredentialTag]cloud.Credential, ) (*state.State, names.UserTag) { owner := names.NewUserTag("test@remote") cfg, _ := createTestModelConfig(c, "") var controllerRegion string var controllerCredential names.CloudCredentialTag if len(regions) > 0 { controllerRegion = regions[0].Name } if len(credentials) > 0 { // pick an arbitrary credential for controllerCredential = range credentials { } } controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ Owner: owner, Config: cfg, CloudName: "dummy", CloudRegion: controllerRegion, CloudCredential: controllerCredential, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: authTypes, Regions: regions, }, CloudCredentials: credentials, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, jc.ErrorIsNil) return st, owner }
func (s *factorySuite) SetUpTest(c *gc.C) { s.BaseSuite.SetUpTest(c) s.MgoSuite.SetUpTest(c) policy := statetesting.MockPolicy{} info := &state.Info{ Info: mongo.Info{ Addrs: []string{jtesting.MgoServer.Addr()}, CACert: testing.CACert, }, } opts := mongo.DialOpts{ Timeout: testing.LongWait, } cfg := testing.EnvironConfig(c) st, err := state.Initialize(info, cfg, opts, &policy) c.Assert(err, gc.IsNil) s.State = st s.Factory = factory.NewFactory(s.State, c) }
func (s *InitializeSuite) TestDoubleInitializeConfig(c *gc.C) { cfg := testing.EnvironConfig(c) initial := cfg.AllAttrs() st := TestingInitialize(c, cfg, nil) st.Close() // A second initialize returns an open *State, but ignores its params. // TODO(fwereade) I think this is crazy, but it's what we were testing // for originally... cfg, err := cfg.Apply(map[string]interface{}{"authorized-keys": "something-else"}) c.Assert(err, gc.IsNil) st, err = state.Initialize(state.TestingMongoInfo(), cfg, state.TestingDialOpts(), state.Policy(nil)) c.Assert(err, gc.IsNil) c.Assert(st, gc.NotNil) st.Close() s.openState(c) cfg, err = s.State.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, initial) }
func (s *InitializeSuite) TestEnvironConfigWithAdminSecret(c *gc.C) { // admin-secret blocks Initialize. good := testing.EnvironConfig(c) badUpdateAttrs := map[string]interface{}{"admin-secret": "foo"} bad, err := good.Apply(badUpdateAttrs) _, err = state.Initialize(state.TestingMongoInfo(), bad, state.TestingDialOpts(), state.Policy(nil)) c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state") // admin-secret blocks UpdateEnvironConfig. st := TestingInitialize(c, good, nil) st.Close() s.openState(c) err = s.State.UpdateEnvironConfig(badUpdateAttrs, nil, nil) c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state") // EnvironConfig remains inviolate. cfg, err := s.State.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, good.AllAttrs()) }
func (s *InitializeSuite) TestModelConfigWithAdminSecret(c *gc.C) { // admin-secret blocks Initialize. good := testing.ModelConfig(c) badUpdateAttrs := map[string]interface{}{"admin-secret": "foo"} bad, err := good.Apply(badUpdateAttrs) owner := names.NewLocalUserTag("initialize-admin") _, err = state.Initialize(owner, statetesting.NewMongoInfo(), bad, statetesting.NewDialOpts(), state.Policy(nil)) c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state") // admin-secret blocks UpdateModelConfig. st := statetesting.Initialize(c, owner, good, nil) st.Close() s.openState(c, st.ModelTag()) err = s.State.UpdateModelConfig(badUpdateAttrs, nil, nil) c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state") // ModelConfig remains inviolate. cfg, err := s.State.ModelConfig() c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.AllAttrs(), gc.DeepEquals, good.AllAttrs()) }
func (s *InitializeSuite) TestCloudConfigWithForbiddenValues(c *gc.C) { badAttrNames := []string{ "admin-secret", "ca-private-key", config.AgentVersionKey, } for _, attr := range controller.ControllerOnlyConfigAttributes { badAttrNames = append(badAttrNames, attr) } modelCfg := testing.ModelConfig(c) controllerCfg := testing.FakeControllerConfig() args := state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ CloudName: "dummy", Owner: names.NewLocalUserTag("initialize-admin"), Config: modelCfg, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, }, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), } for _, badAttrName := range badAttrNames { badAttrs := map[string]interface{}{badAttrName: "foo"} args.ControllerInheritedConfig = badAttrs _, err := state.Initialize(args) c.Assert(err, gc.ErrorMatches, "local cloud config cannot contain .*") } }
func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) error { selectedTools, err := common.EnsureBootstrapTools(ctx, e, config.PreferredSeries(e.Config()), args.Constraints.Arch) if err != nil { return err } series := selectedTools.OneSeries() defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } network.InitializeFromConfig(e.Config()) password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } logger.Infof("would pick tools from %s", selectedTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } estate, err := e.state() if err != nil { return err } estate.mu.Lock() defer estate.mu.Unlock() if estate.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } estate.preferIPv6 = e.Config().PreferIPv6() // Write the bootstrap file just like a normal provider. However // we need to release the mutex for the save state to work, so regain // it after the call. estate.mu.Unlock() instIds := []instance.Id{BootstrapInstanceId} if err := bootstrap.SaveState(e.Storage(), &bootstrap.BootstrapState{StateInstances: instIds}); err != nil { logger.Errorf("failed to save state instances: %v", err) estate.mu.Lock() // otherwise defered unlock will fail return err } estate.mu.Lock() // back at it // Create an instance for the bootstrap node. logger.Infof("creating bootstrap instance") i := &dummyInstance{ id: BootstrapInstanceId, addresses: network.NewAddresses("localhost"), ports: make(map[network.Port]bool), machineId: agent.BootstrapMachineId, series: series, firewallMode: e.Config().FirewallMode(), state: estate, stateServer: true, } estate.insts[i.id] = i if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo(estate.preferIPv6) st, err := state.Initialize(info, cfg, mongo.DefaultDialOpts(), estate.statePolicy) if err != nil { panic(err) } if err := st.SetEnvironConstraints(args.Constraints); err != nil { panic(err) } if err := st.SetAdminMongoPassword(utils.UserPasswordHash(password, utils.CompatSalt)); err != nil { panic(err) } _, err = st.AddAdminUser(password) if err != nil { panic(err) } estate.apiServer, err = apiserver.NewServer(st, estate.apiListener, apiserver.ServerConfig{ Cert: []byte(testing.ServerCert), Key: []byte(testing.ServerKey), DataDir: DataDir, LogDir: LogDir, }) if err != nil { panic(err) } estate.apiState = st } estate.bootstrapped = true estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args} return nil }
func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) { series := config.PreferredSeries(e.Config()) availableTools, err := args.AvailableTools.Match(coretools.Filter{Series: series}) if err != nil { return nil, err } arch := availableTools.Arches()[0] defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return nil, err } if _, ok := args.ControllerConfig.CACert(); !ok { return nil, errors.New("no CA certificate in controller configuration") } logger.Infof("would pick tools from %s", availableTools) estate, err := e.state() if err != nil { return nil, err } estate.mu.Lock() defer estate.mu.Unlock() if estate.bootstrapped { return nil, errors.New("model is already bootstrapped") } // Create an instance for the bootstrap node. logger.Infof("creating bootstrap instance") i := &dummyInstance{ id: BootstrapInstanceId, addresses: network.NewAddresses("localhost"), ports: make(map[network.PortRange]bool), machineId: agent.BootstrapMachineId, series: series, firewallMode: e.Config().FirewallMode(), state: estate, controller: true, } estate.insts[i.id] = i estate.bootstrapped = true estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args} finalize := func(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig, _ environs.BootstrapDialOpts) error { if e.ecfg().controller() { icfg.Bootstrap.BootstrapMachineInstanceId = BootstrapInstanceId if err := instancecfg.FinishInstanceConfig(icfg, e.Config()); err != nil { return err } adminUser := names.NewUserTag("admin@local") var cloudCredentialTag names.CloudCredentialTag if icfg.Bootstrap.ControllerCloudCredentialName != "" { cloudCredentialTag = names.NewCloudCredentialTag(fmt.Sprintf( "%s/%s/%s", icfg.Bootstrap.ControllerCloudName, adminUser.Id(), icfg.Bootstrap.ControllerCloudCredentialName, )) } cloudCredentials := make(map[names.CloudCredentialTag]cloud.Credential) if icfg.Bootstrap.ControllerCloudCredential != nil && icfg.Bootstrap.ControllerCloudCredentialName != "" { cloudCredentials[cloudCredentialTag] = *icfg.Bootstrap.ControllerCloudCredential } info := stateInfo() // Since the admin user isn't setup until after here, // the password in the info structure is empty, so the admin // user is constructed with an empty password here. // It is set just below. st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: icfg.Controller.Config, ControllerModelArgs: state.ModelArgs{ Owner: adminUser, Config: icfg.Bootstrap.ControllerModelConfig, Constraints: icfg.Bootstrap.BootstrapMachineConstraints, CloudName: icfg.Bootstrap.ControllerCloudName, CloudRegion: icfg.Bootstrap.ControllerCloudRegion, CloudCredential: cloudCredentialTag, StorageProviderRegistry: e, }, Cloud: icfg.Bootstrap.ControllerCloud, CloudName: icfg.Bootstrap.ControllerCloudName, CloudCredentials: cloudCredentials, MongoInfo: info, MongoDialOpts: mongotest.DialOpts(), NewPolicy: estate.newStatePolicy, }) if err != nil { return err } if err := st.SetModelConstraints(args.ModelConstraints); err != nil { return err } if err := st.SetAdminMongoPassword(icfg.Controller.MongoInfo.Password); err != nil { return err } if err := st.MongoSession().DB("admin").Login("admin", icfg.Controller.MongoInfo.Password); err != nil { return err } env, err := st.Model() if err != nil { return err } owner, err := st.User(env.Owner()) if err != nil { return err } // We log this out for test purposes only. No one in real life can use // a dummy provider for anything other than testing, so logging the password // here is fine. logger.Debugf("setting password for %q to %q", owner.Name(), icfg.Controller.MongoInfo.Password) owner.SetPassword(icfg.Controller.MongoInfo.Password) estate.apiStatePool = state.NewStatePool(st) estate.apiServer, err = apiserver.NewServer(st, estate.apiListener, apiserver.ServerConfig{ Clock: clock.WallClock, Cert: testing.ServerCert, Key: testing.ServerKey, Tag: names.NewMachineTag("0"), DataDir: DataDir, LogDir: LogDir, StatePool: estate.apiStatePool, NewObserver: func() observer.Observer { return &fakeobserver.Instance{} }, // Should never be used but prevent external access just in case. AutocertURL: "https://0.1.2.3/no-autocert-here", }) if err != nil { panic(err) } estate.apiState = st } estate.ops <- OpFinalizeBootstrap{Context: ctx, Env: e.name, InstanceConfig: icfg} return nil } bsResult := &environs.BootstrapResult{ Arch: arch, Series: series, Finalize: finalize, } return bsResult, nil }
func (s *InitializeSuite) TestInitialize(c *gc.C) { cfg := testing.ModelConfig(c) uuid := cfg.UUID() owner := names.NewLocalUserTag("initialize-admin") userPassCredentialTag := names.NewCloudCredentialTag( "dummy/" + owner.Canonical() + "/some-credential", ) emptyCredentialTag := names.NewCloudCredentialTag( "dummy/" + owner.Canonical() + "/empty-credential", ) userpassCredential := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "username": "******", "password": "******", }, ) userpassCredential.Label = userPassCredentialTag.Name() emptyCredential := cloud.NewEmptyCredential() emptyCredential.Label = emptyCredentialTag.Name() cloudCredentialsIn := map[names.CloudCredentialTag]cloud.Credential{ userPassCredentialTag: userpassCredential, emptyCredentialTag: emptyCredential, } controllerCfg := testing.FakeControllerConfig() st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerConfig: controllerCfg, ControllerModelArgs: state.ModelArgs{ Owner: owner, Config: cfg, CloudName: "dummy", CloudRegion: "dummy-region", CloudCredential: userPassCredentialTag, StorageProviderRegistry: storage.StaticProviderRegistry{}, }, CloudName: "dummy", Cloud: cloud.Cloud{ Type: "dummy", AuthTypes: []cloud.AuthType{ cloud.EmptyAuthType, cloud.UserPassAuthType, }, Regions: []cloud.Region{{Name: "dummy-region"}}, }, CloudCredentials: cloudCredentialsIn, MongoInfo: statetesting.NewMongoInfo(), MongoDialOpts: mongotest.DialOpts(), }) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.NotNil) modelTag := st.ModelTag() c.Assert(modelTag.Id(), gc.Equals, uuid) err = st.Close() c.Assert(err, jc.ErrorIsNil) s.openState(c, modelTag) cfg, err = s.State.ModelConfig() c.Assert(err, jc.ErrorIsNil) expected := cfg.AllAttrs() for k, v := range config.ConfigDefaults() { if _, ok := expected[k]; !ok { expected[k] = v } } c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected) // Check that the model has been created. model, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(model.Tag(), gc.Equals, modelTag) c.Assert(model.CloudRegion(), gc.Equals, "dummy-region") // Check that the owner has been created. c.Assert(model.Owner(), gc.Equals, owner) // Check that the owner can be retrieved by the tag. entity, err := s.State.FindEntity(model.Owner()) c.Assert(err, jc.ErrorIsNil) c.Assert(entity.Tag(), gc.Equals, owner) // Check that the owner has an ModelUser created for the bootstrapped model. modelUser, err := s.State.UserAccess(model.Owner(), model.Tag()) c.Assert(err, jc.ErrorIsNil) c.Assert(modelUser.UserTag, gc.Equals, owner) c.Assert(modelUser.Object, gc.Equals, model.Tag()) // Check that the model can be found through the tag. entity, err = s.State.FindEntity(modelTag) c.Assert(err, jc.ErrorIsNil) cons, err := s.State.ModelConstraints() c.Assert(err, jc.ErrorIsNil) c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) addrs, err := s.State.APIHostPorts() c.Assert(err, jc.ErrorIsNil) c.Assert(addrs, gc.HasLen, 0) info, err := s.State.ControllerInfo() c.Assert(err, jc.ErrorIsNil) c.Assert(info, jc.DeepEquals, &state.ControllerInfo{ModelTag: modelTag, CloudName: "dummy"}) // Check that the model's cloud and credential names are as // expected, and the owner's cloud credentials are initialised. c.Assert(model.Cloud(), gc.Equals, "dummy") credentialTag, ok := model.CloudCredential() c.Assert(ok, jc.IsTrue) c.Assert(credentialTag, gc.Equals, userPassCredentialTag) cloudCredentials, err := s.State.CloudCredentials(model.Owner(), "dummy") c.Assert(err, jc.ErrorIsNil) expectedCred := make(map[string]cloud.Credential, len(cloudCredentialsIn)) for tag, cred := range cloudCredentialsIn { expectedCred[tag.Canonical()] = cred } c.Assert(cloudCredentials, jc.DeepEquals, expectedCred) }
// InitializeState should be called on the bootstrap machine's agent // configuration. It uses that information to create the controller, dial the // controller, and initialize it. It also generates a new password for the // bootstrap machine and calls Write to save the the configuration. // // The cfg values will be stored in the state's ModelConfig; the // machineCfg values will be used to configure the bootstrap Machine, // and its constraints will be also be used for the model-level // constraints. The connection to the controller will respect the // given timeout parameter. // // InitializeState returns the newly initialized state and bootstrap // machine. If it fails, the state may well be irredeemably compromised. func InitializeState( adminUser names.UserTag, c agent.ConfigSetter, cfg *config.Config, hostedModelConfigAttrs map[string]interface{}, machineCfg BootstrapMachineConfig, dialOpts mongo.DialOpts, policy state.Policy, ) (_ *state.State, _ *state.Machine, resultErr error) { if c.Tag() != names.NewMachineTag(agent.BootstrapMachineId) { return nil, nil, errors.Errorf("InitializeState not called with bootstrap machine's configuration") } servingInfo, ok := c.StateServingInfo() if !ok { return nil, nil, errors.Errorf("state serving information not available") } // N.B. no users are set up when we're initializing the state, // so don't use any tag or password when opening it. info, ok := c.MongoInfo() if !ok { return nil, nil, errors.Errorf("stateinfo not available") } info.Tag = nil info.Password = c.OldPassword() if err := initMongoAdminUser(info.Info, dialOpts, info.Password); err != nil { return nil, nil, errors.Annotate(err, "failed to initialize mongo admin user") } logger.Debugf("initializing address %v", info.Addrs) st, err := state.Initialize(adminUser, info, cfg, dialOpts, policy) if err != nil { return nil, nil, errors.Errorf("failed to initialize state: %v", err) } logger.Debugf("connected to initial state") defer func() { if resultErr != nil { st.Close() } }() servingInfo.SharedSecret = machineCfg.SharedSecret c.SetStateServingInfo(servingInfo) // Filter out any LXC bridge addresses from the machine addresses. machineCfg.Addresses = network.FilterLXCAddresses(machineCfg.Addresses) if err = initAPIHostPorts(c, st, machineCfg.Addresses, servingInfo.APIPort); err != nil { return nil, nil, err } ssi := paramsStateServingInfoToStateStateServingInfo(servingInfo) if err := st.SetStateServingInfo(ssi); err != nil { return nil, nil, errors.Errorf("cannot set state serving info: %v", err) } m, err := initConstraintsAndBootstrapMachine(c, st, machineCfg) if err != nil { return nil, nil, err } // Create the initial hosted model, with the model config passed to // bootstrap, which contains the UUID, name for the hosted model, // and any user supplied config. attrs := make(map[string]interface{}) for k, v := range hostedModelConfigAttrs { attrs[k] = v } hostedModelConfig, err := modelmanager.ModelConfigCreator{}.NewModelConfig(modelmanager.IsAdmin, cfg, attrs) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model config") } _, hostedModelState, err := st.NewModel(hostedModelConfig, adminUser) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model") } if err := hostedModelState.SetModelConstraints(machineCfg.ModelConstraints); err != nil { return nil, nil, errors.Annotate(err, "cannot set initial hosted model constraints") } hostedModelState.Close() return st, m, nil }
func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (arch, series string, _ environs.BootstrapFinalizer, _ error) { series = config.PreferredSeries(e.Config()) availableTools, err := args.AvailableTools.Match(coretools.Filter{Series: series}) if err != nil { return "", "", nil, err } arch = availableTools.Arches()[0] defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return "", "", nil, err } network.InitializeFromConfig(e.Config()) password := e.Config().AdminSecret() if password == "" { return "", "", nil, fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return "", "", nil, fmt.Errorf("no CA certificate in environment configuration") } logger.Infof("would pick tools from %s", availableTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return "", "", nil, fmt.Errorf("cannot make bootstrap config: %v", err) } estate, err := e.state() if err != nil { return "", "", nil, err } estate.mu.Lock() defer estate.mu.Unlock() if estate.bootstrapped { return "", "", nil, fmt.Errorf("environment is already bootstrapped") } estate.preferIPv6 = e.Config().PreferIPv6() // Create an instance for the bootstrap node. logger.Infof("creating bootstrap instance") i := &dummyInstance{ id: BootstrapInstanceId, addresses: network.NewAddresses("localhost"), ports: make(map[network.PortRange]bool), machineId: agent.BootstrapMachineId, series: series, firewallMode: e.Config().FirewallMode(), state: estate, stateServer: true, } estate.insts[i.id] = i if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo(estate.preferIPv6) // Since the admin user isn't setup until after here, // the password in the info structure is empty, so the admin // user is constructed with an empty password here. // It is set just below. st, err := state.Initialize( AdminUserTag(), info, cfg, mongo.DefaultDialOpts(), estate.statePolicy) if err != nil { panic(err) } if err := st.SetEnvironConstraints(args.Constraints); err != nil { panic(err) } if err := st.SetAdminMongoPassword(password); err != nil { panic(err) } if err := st.MongoSession().DB("admin").Login("admin", password); err != nil { panic(err) } env, err := st.Environment() if err != nil { panic(err) } owner, err := st.User(env.Owner()) if err != nil { panic(err) } // We log this out for test purposes only. No one in real life can use // a dummy provider for anything other than testing, so logging the password // here is fine. logger.Debugf("setting password for %q to %q", owner.Name(), password) owner.SetPassword(password) estate.apiServer, err = apiserver.NewServer(st, estate.apiListener, apiserver.ServerConfig{ Cert: []byte(testing.ServerCert), Key: []byte(testing.ServerKey), Tag: names.NewMachineTag("0"), DataDir: DataDir, LogDir: LogDir, }) if err != nil { panic(err) } estate.apiState = st } estate.bootstrapped = true estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args} finalize := func(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig) error { estate.ops <- OpFinalizeBootstrap{Context: ctx, Env: e.name, InstanceConfig: icfg} return nil } return arch, series, finalize, nil }
func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (arch, series string, _ environs.BootstrapFinalizer, _ error) { series = config.PreferredSeries(e.Config()) availableTools, err := args.AvailableTools.Match(coretools.Filter{Series: series}) if err != nil { return "", "", nil, err } arch = availableTools.Arches()[0] defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return "", "", nil, err } network.InitializeFromConfig(e.Config()) password := e.Config().AdminSecret() if password == "" { return "", "", nil, fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return "", "", nil, fmt.Errorf("no CA certificate in environment configuration") } logger.Infof("would pick tools from %s", availableTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return "", "", nil, fmt.Errorf("cannot make bootstrap config: %v", err) } estate, err := e.state() if err != nil { return "", "", nil, err } estate.mu.Lock() defer estate.mu.Unlock() if estate.bootstrapped { return "", "", nil, fmt.Errorf("environment is already bootstrapped") } estate.preferIPv6 = e.Config().PreferIPv6() // Create an instance for the bootstrap node. logger.Infof("creating bootstrap instance") i := &dummyInstance{ id: BootstrapInstanceId, addresses: network.NewAddresses("localhost"), ports: make(map[network.PortRange]bool), machineId: agent.BootstrapMachineId, series: series, firewallMode: e.Config().FirewallMode(), state: estate, stateServer: true, } estate.insts[i.id] = i if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo(estate.preferIPv6) st, err := state.Initialize(info, cfg, mongo.DefaultDialOpts(), estate.statePolicy) if err != nil { panic(err) } if err := st.SetEnvironConstraints(args.Constraints); err != nil { panic(err) } if err := st.SetAdminMongoPassword(password); err != nil { panic(err) } if err := st.MongoSession().DB("admin").Login("admin", password); err != nil { panic(err) } _, err = st.AddAdminUser(password) if err != nil { panic(err) } estate.apiServer, err = apiserver.NewServer(st, estate.apiListener, apiserver.ServerConfig{ Cert: []byte(testing.ServerCert), Key: []byte(testing.ServerKey), DataDir: DataDir, LogDir: LogDir, }) if err != nil { panic(err) } estate.apiState = st } estate.bootstrapped = true estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args} finalize := func(ctx environs.BootstrapContext, mcfg *cloudinit.MachineConfig) error { estate.ops <- OpFinalizeBootstrap{Context: ctx, Env: e.name, MachineConfig: mcfg} return nil } return arch, series, finalize, nil }
// InitializeState should be called on the bootstrap machine's agent // configuration. It uses that information to create the controller, dial the // controller, and initialize it. It also generates a new password for the // bootstrap machine and calls Write to save the the configuration. // // The cfg values will be stored in the state's ModelConfig; the // machineCfg values will be used to configure the bootstrap Machine, // and its constraints will be also be used for the model-level // constraints. The connection to the controller will respect the // given timeout parameter. // // InitializeState returns the newly initialized state and bootstrap // machine. If it fails, the state may well be irredeemably compromised. func InitializeState( adminUser names.UserTag, c agent.ConfigSetter, args InitializeStateParams, dialOpts mongo.DialOpts, newPolicy state.NewPolicyFunc, ) (_ *state.State, _ *state.Machine, resultErr error) { if c.Tag() != names.NewMachineTag(agent.BootstrapMachineId) { return nil, nil, errors.Errorf("InitializeState not called with bootstrap machine's configuration") } servingInfo, ok := c.StateServingInfo() if !ok { return nil, nil, errors.Errorf("state serving information not available") } // N.B. no users are set up when we're initializing the state, // so don't use any tag or password when opening it. info, ok := c.MongoInfo() if !ok { return nil, nil, errors.Errorf("stateinfo not available") } info.Tag = nil info.Password = c.OldPassword() if err := initMongoAdminUser(info.Info, dialOpts, info.Password); err != nil { return nil, nil, errors.Annotate(err, "failed to initialize mongo admin user") } cloudCredentials := make(map[names.CloudCredentialTag]cloud.Credential) var cloudCredentialTag names.CloudCredentialTag if args.ControllerCloudCredential != nil && args.ControllerCloudCredentialName != "" { cloudCredentialTag = names.NewCloudCredentialTag(fmt.Sprintf( "%s/%s/%s", args.ControllerCloudName, adminUser.Canonical(), args.ControllerCloudCredentialName, )) cloudCredentials[cloudCredentialTag] = *args.ControllerCloudCredential } logger.Debugf("initializing address %v", info.Addrs) st, err := state.Initialize(state.InitializeParams{ Clock: clock.WallClock, ControllerModelArgs: state.ModelArgs{ Owner: adminUser, Config: args.ControllerModelConfig, Constraints: args.ModelConstraints, CloudName: args.ControllerCloudName, CloudRegion: args.ControllerCloudRegion, CloudCredential: cloudCredentialTag, StorageProviderRegistry: args.StorageProviderRegistry, }, CloudName: args.ControllerCloudName, Cloud: args.ControllerCloud, CloudCredentials: cloudCredentials, ControllerConfig: args.ControllerConfig, ControllerInheritedConfig: args.ControllerInheritedConfig, RegionInheritedConfig: args.RegionInheritedConfig, MongoInfo: info, MongoDialOpts: dialOpts, NewPolicy: newPolicy, }) if err != nil { return nil, nil, errors.Errorf("failed to initialize state: %v", err) } logger.Debugf("connected to initial state") defer func() { if resultErr != nil { st.Close() } }() servingInfo.SharedSecret = args.SharedSecret c.SetStateServingInfo(servingInfo) // Filter out any LXC or LXD bridge addresses from the machine addresses. args.BootstrapMachineAddresses = network.FilterBridgeAddresses(args.BootstrapMachineAddresses) if err = initAPIHostPorts(c, st, args.BootstrapMachineAddresses, servingInfo.APIPort); err != nil { return nil, nil, err } ssi := paramsStateServingInfoToStateStateServingInfo(servingInfo) if err := st.SetStateServingInfo(ssi); err != nil { return nil, nil, errors.Errorf("cannot set state serving info: %v", err) } m, err := initBootstrapMachine(c, st, args) if err != nil { return nil, nil, errors.Annotate(err, "cannot initialize bootstrap machine") } // Create the initial hosted model, with the model config passed to // bootstrap, which contains the UUID, name for the hosted model, // and any user supplied config. We also copy the authorized-keys // from the controller model. attrs := make(map[string]interface{}) for k, v := range args.HostedModelConfig { attrs[k] = v } attrs[config.AuthorizedKeysKey] = args.ControllerModelConfig.AuthorizedKeys() // Construct a CloudSpec to pass on to NewModelConfig below. cloudSpec, err := environs.MakeCloudSpec( args.ControllerCloud, args.ControllerCloudName, args.ControllerCloudRegion, args.ControllerCloudCredential, ) if err != nil { return nil, nil, errors.Trace(err) } controllerUUID := args.ControllerConfig.ControllerUUID() creator := modelmanager.ModelConfigCreator{Provider: args.Provider} hostedModelConfig, err := creator.NewModelConfig( cloudSpec, args.ControllerModelConfig, attrs, ) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model config") } provider, err := args.Provider(cloudSpec.Type) if err != nil { return nil, nil, errors.Annotate(err, "getting environ provider") } hostedModelEnv, err := provider.Open(environs.OpenParams{ Cloud: cloudSpec, Config: hostedModelConfig, }) if err != nil { return nil, nil, errors.Annotate(err, "opening hosted model environment") } if err := hostedModelEnv.Create(environs.CreateParams{ ControllerUUID: controllerUUID, }); err != nil { return nil, nil, errors.Annotate(err, "creating hosted model environment") } _, hostedModelState, err := st.NewModel(state.ModelArgs{ Owner: adminUser, Config: hostedModelConfig, Constraints: args.ModelConstraints, CloudName: args.ControllerCloudName, CloudRegion: args.ControllerCloudRegion, CloudCredential: cloudCredentialTag, StorageProviderRegistry: args.StorageProviderRegistry, }) if err != nil { return nil, nil, errors.Annotate(err, "creating hosted model") } hostedModelState.Close() return st, m, nil }