// newState returns a new State that uses the given environment. // The environment must have already been bootstrapped. func newState(environ environs.Environ, mongoInfo *mongo.MongoInfo) (*state.State, error) { config := environ.Config() password := config.AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } modelTag := names.NewModelTag(config.UUID()) mongoInfo.Password = password opts := mongo.DefaultDialOpts() st, err := state.Open(modelTag, mongoInfo, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(errors.Cause(err)) { // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(modelTag, mongoInfo, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(errors.Cause(err)) { break } } if err != nil { return nil, err } } else if err != nil { return nil, err } if err := updateSecrets(environ, st); err != nil { st.Close() return nil, fmt.Errorf("unable to push secrets: %v", err) } return st, nil }
func (s *BootstrapSuite) TestInitialPassword(c *gc.C) { machineConf, cmd, err := s.initBootstrapCommand(c, nil, "--model-config", s.b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) info := &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, } // Check we can log in to mongo as admin. // TODO(dfc) does passing nil for the admin user name make your skin crawl ? mine too. info.Tag, info.Password = nil, testPassword st, err := state.Open(testing.ModelTag, info, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() // We're running Mongo with --noauth; let's explicitly verify // that we can login as that user. Even with --noauth, an // explicit Login will still be verified. adminDB := st.MongoSession().DB("admin") err = adminDB.Login("admin", "invalid-password") c.Assert(err, gc.ErrorMatches, "(auth|(.*Authentication)) fail(s|ed)\\.?") err = adminDB.Login("admin", info.Password) c.Assert(err, jc.ErrorIsNil) // Check that the admin user has been given an appropriate // password u, err := st.User(names.NewLocalUserTag("admin")) c.Assert(err, jc.ErrorIsNil) c.Assert(u.PasswordValid(testPassword), jc.IsTrue) // Check that the machine configuration has been given a new // password and that we can connect to mongo as that machine // and that the in-mongo password also verifies correctly. machineConf1, err := agent.ReadConfig(agent.ConfigPath(machineConf.DataDir(), names.NewMachineTag("0"))) c.Assert(err, jc.ErrorIsNil) stateinfo, ok := machineConf1.MongoInfo() c.Assert(ok, jc.IsTrue) st, err = state.Open(testing.ModelTag, stateinfo, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, jc.ErrorIsNil) c.Assert(m.HasVote(), jc.IsTrue) }
// NewConn returns a new Conn that uses the // given environment. The environment must have already // been bootstrapped. func NewConn(environ environs.Environ) (*Conn, error) { info, _, err := environ.StateInfo() if err != nil { return nil, err } password := environ.Config().AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } err = environs.CheckEnvironment(environ) if err != nil { return nil, err } info.Password = password opts := mongo.DefaultDialOpts() st, err := state.Open(info, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(err) { logger.Infof("authorization error while connecting to state server; retrying") // We can't connect with the administrator password,; // perhaps this was the first connection and the // password has not been changed yet. info.Password = utils.UserPasswordHash(password, utils.CompatSalt) // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(info, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(err) { break } } if err != nil { return nil, err } if err := st.SetAdminMongoPassword(password); err != nil { return nil, err } } else if err != nil { return nil, err } conn := &Conn{ Environ: environ, State: st, } if err := conn.updateSecrets(); err != nil { conn.Close() return nil, fmt.Errorf("unable to push secrets: %v", err) } return conn, nil }
func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) { dataDir := c.MkDir() pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt) configParams := agent.AgentConfigParams{ DataDir: dataDir, Tag: "machine-0", UpgradedToVersion: version.Current.Number, StateAddresses: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, Password: pwHash, } cfg, err := agent.NewAgentConfig(configParams) c.Assert(err, gc.IsNil) cfg.SetStateServingInfo(params.StateServingInfo{ APIPort: 5555, StatePort: gitjujutesting.MgoServer.Port(), Cert: "foo", PrivateKey: "bar", SharedSecret: "baz", SystemIdentity: "qux", }) expectConstraints := constraints.MustParse("mem=1024M") expectHW := instance.MustParseHardware("mem=2048M") mcfg := agent.BootstrapMachineConfig{ Constraints: expectConstraints, Jobs: []params.MachineJob{params.JobHostUnits}, InstanceId: "i-bootstrap", Characteristics: expectHW, } envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{ "agent-version": version.Current.Number.String(), "state-id": "1", // needed so policy can Open config }) envCfg, err := config.New(config.NoDefaults, envAttrs) c.Assert(err, gc.IsNil) st, _, err := agent.InitializeState(cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) err = st.SetAdminMongoPassword("") c.Check(err, gc.IsNil) st.Close() st, _, err = agent.InitializeState(cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) if err == nil { st.Close() } c.Assert(err, gc.ErrorMatches, "failed to initialize state: cannot create log collection: unauthorized mongo access: unauthorized") }
func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) { dataDir := c.MkDir() pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt) configParams := agent.AgentConfigParams{ DataDir: dataDir, Tag: names.NewMachineTag("0"), UpgradedToVersion: version.Current.Number, StateAddresses: []string{s.mgoInst.Addr()}, CACert: testing.CACert, Password: pwHash, Environment: testing.EnvironmentTag, } cfg, err := agent.NewAgentConfig(configParams) c.Assert(err, jc.ErrorIsNil) cfg.SetStateServingInfo(params.StateServingInfo{ APIPort: 5555, StatePort: s.mgoInst.Port(), Cert: "foo", PrivateKey: "bar", SharedSecret: "baz", SystemIdentity: "qux", }) expectConstraints := constraints.MustParse("mem=1024M") expectHW := instance.MustParseHardware("mem=2048M") mcfg := agent.BootstrapMachineConfig{ Constraints: expectConstraints, Jobs: []multiwatcher.MachineJob{multiwatcher.JobManageEnviron}, InstanceId: "i-bootstrap", Characteristics: expectHW, } envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{ "agent-version": version.Current.Number.String(), "state-id": "1", // needed so policy can Open config }) envCfg, err := config.New(config.NoDefaults, envAttrs) c.Assert(err, jc.ErrorIsNil) adminUser := names.NewLocalUserTag("agent-admin") st, _, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) st.Close() st, _, err = agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy()) if err == nil { st.Close() } c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*") }
func (s *BootstrapSuite) TestInitialPassword(c *gc.C) { machineConf, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", s.envcfg, "--instance-id", string(s.instanceId)) c.Assert(err, gc.IsNil) err = cmd.Run(nil) c.Assert(err, gc.IsNil) // Check that we cannot now connect to the state without a // password. info := &authentication.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, } testOpenState(c, info, errors.Unauthorizedf("")) // Check we can log in to mongo as admin. // TODO(dfc) does passing nil for the admin user name make your skin crawl ? mine too. info.Tag, info.Password = nil, testPasswordHash() st, err := state.Open(info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) // Reset password so the tests can continue to use the same server. defer st.Close() defer st.SetAdminMongoPassword("") // Check that the admin user has been given an appropriate // password u, err := st.User("admin") c.Assert(err, gc.IsNil) c.Assert(u.PasswordValid(testPassword), gc.Equals, true) // Check that the machine configuration has been given a new // password and that we can connect to mongo as that machine // and that the in-mongo password also verifies correctly. machineConf1, err := agent.ReadConfig(agent.ConfigPath(machineConf.DataDir(), names.NewMachineTag("0"))) c.Assert(err, gc.IsNil) stateinfo, ok := machineConf1.MongoInfo() c.Assert(ok, jc.IsTrue) st, err = state.Open(stateinfo, mongo.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, gc.IsNil) c.Assert(m.HasVote(), jc.IsTrue) }
func (s *BootstrapSuite) TestSetConstraints(c *gc.C) { tcons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)} _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", s.b64yamlEnvcfg, "--instance-id", string(s.instanceId), "--constraints", tcons.String(), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) st, err := state.Open(testing.EnvironmentTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPasswordHash(), }, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() cons, err := st.EnvironConstraints() c.Assert(err, jc.ErrorIsNil) c.Assert(cons, gc.DeepEquals, tcons) machines, err := st.AllMachines() c.Assert(err, jc.ErrorIsNil) c.Assert(machines, gc.HasLen, 1) cons, err = machines[0].Constraints() c.Assert(err, jc.ErrorIsNil) c.Assert(cons, gc.DeepEquals, tcons) }
func tryOpenState(info *mongo.MongoInfo) error { st, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) if err == nil { st.Close() } return err }
func tryOpenState(modelTag names.ModelTag, info *mongo.MongoInfo) error { st, err := state.Open(modelTag, info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if err == nil { st.Close() } return err }
// Run implements cmd.Command. func (c *dumpLogsCommand) Run(ctx *cmd.Context) error { config := c.agentConfig.CurrentConfig() info, ok := config.MongoInfo() if !ok { return errors.New("no database connection info available (is this a controller host?)") } st0, err := state.Open(config.Environment(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if err != nil { return errors.Annotate(err, "failed to connect to database") } defer st0.Close() envs, err := st0.AllEnvironments() if err != nil { return errors.Annotate(err, "failed to look up environments") } for _, env := range envs { err := c.dumpLogsForEnv(ctx, st0, env.EnvironTag()) if err != nil { return errors.Annotatef(err, "failed to dump logs for environment %s", env.UUID()) } } return nil }
func (s *BootstrapSuite) TestDefaultMachineJobs(c *gc.C) { expectedJobs := []state.MachineJob{ state.JobManageModel, state.JobHostUnits, state.JobManageNetworking, } _, cmd, err := s.initBootstrapCommand(c, nil, "--model-config", s.b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) st, err := state.Open(testing.ModelTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPassword, }, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, jc.ErrorIsNil) c.Assert(m.Jobs(), gc.DeepEquals, expectedJobs) }
func openState(agentConfig agent.Config, dialOpts mongo.DialOpts) (_ *state.State, _ *state.Machine, err error) { info, ok := agentConfig.MongoInfo() if !ok { return nil, nil, fmt.Errorf("no state info available") } st, err := state.Open(agentConfig.Model(), info, dialOpts, environs.NewStatePolicy()) if err != nil { return nil, nil, err } defer func() { if err != nil { st.Close() } }() m0, err := st.FindEntity(agentConfig.Tag()) if err != nil { if errors.IsNotFound(err) { err = worker.ErrTerminateAgent } return nil, nil, err } m := m0.(*state.Machine) if m.Life() == state.Dead { return nil, nil, worker.ErrTerminateAgent } // Check the machine nonce as provisioned matches the agent.Conf value. if !m.CheckProvisioned(agentConfig.Nonce()) { // The agent is running on a different machine to the one it // should be according to state. It must stop immediately. logger.Errorf("running machine %v agent on inappropriate instance", m) return nil, nil, worker.ErrTerminateAgent } return st, m, nil }
func (s *BootstrapSuite) TestInitializeEnvironmentToolsNotFound(c *gc.C) { // bootstrap with 1.99.1 but there will be no tools so version will be reset. envcfg, err := s.envcfg.Apply(map[string]interface{}{ "agent-version": "1.99.1", }) c.Assert(err, jc.ErrorIsNil) b64yamlControllerModelConfig := b64yaml(envcfg.AllAttrs()).encode() hw := instance.MustParseHardware("arch=amd64 mem=8G") _, cmd, err := s.initBootstrapCommand( c, nil, "--model-config", b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), "--hardware", hw.String(), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) st, err := state.Open(testing.ModelTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPassword, }, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() cfg, err := st.ModelConfig() c.Assert(err, jc.ErrorIsNil) vers, ok := cfg.AgentVersion() c.Assert(ok, jc.IsTrue) c.Assert(vers.String(), gc.Equals, "1.99.0") }
func (s *BootstrapSuite) TestSetConstraints(c *gc.C) { bootstrapCons := constraints.Value{Mem: uint64p(4096), CpuCores: uint64p(4)} modelCons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)} _, cmd, err := s.initBootstrapCommand(c, nil, "--model-config", s.b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), "--bootstrap-constraints", bootstrapCons.String(), "--constraints", modelCons.String(), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) st, err := state.Open(testing.ModelTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPassword, }, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() cons, err := st.ModelConstraints() c.Assert(err, jc.ErrorIsNil) c.Assert(cons, gc.DeepEquals, modelCons) machines, err := st.AllMachines() c.Assert(err, jc.ErrorIsNil) c.Assert(machines, gc.HasLen, 1) cons, err = machines[0].Constraints() c.Assert(err, jc.ErrorIsNil) c.Assert(cons, gc.DeepEquals, bootstrapCons) }
func (c *MigrateCommand) Run(ctx *cmd.Context) (err error) { defer func() { if err != nil { fmt.Fprintf(ctx.Stdout, "error stack:\n"+errors.ErrorStack(err)) } }() loggo.GetLogger("juju").SetLogLevel(loggo.DEBUG) conf, err := agent.ReadConfig(agent.ConfigPath(c.dataDir, c.machineTag)) if err != nil { return err } info, ok := conf.MongoInfo() if !ok { return errors.Errorf("no state info available") } st, err := state.Open(conf.Model(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if err != nil { return err } defer st.Close() if c.operation == "export" { return c.exportModel(ctx, st) } return c.importModel(ctx, st) }
func (s *BootstrapSuite) TestDefaultStoragePools(c *gc.C) { _, cmd, err := s.initBootstrapCommand( c, nil, "--model-config", s.b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) st, err := state.Open(testing.ModelTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPassword, }, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() settings := state.NewStateSettings(st) pm := poolmanager.New(settings) for _, p := range []string{"ebs-ssd"} { _, err = pm.Get(p) c.Assert(err, jc.ErrorIsNil) } }
func (s *UpgradeSuite) openStateForUpgrade() (*state.State, func(), error) { mongoInfo := s.State.MongoConnectionInfo() st, err := state.Open(s.State.ModelTag(), mongoInfo, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if err != nil { return nil, nil, err } return st, func() { st.Close() }, nil }
func (s *AgentSuite) AssertCanOpenState(c *gc.C, tag names.Tag, dataDir string) { config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag)) c.Assert(err, jc.ErrorIsNil) info, ok := config.MongoInfo() c.Assert(ok, jc.IsTrue) st, err := state.Open(config.Model(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) st.Close() }
func (s *agentSuite) assertCanOpenState(c *gc.C, tag, dataDir string) { config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag)) c.Assert(err, gc.IsNil) info, ok := config.StateInfo() c.Assert(ok, jc.IsTrue) st, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) st.Close() }
func (*NewConnSuite) TestConnWithPassword(c *gc.C) { attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ "admin-secret": "nutkin", }) cfg, err := config.New(config.NoDefaults, attrs) c.Assert(err, gc.IsNil) ctx := coretesting.Context(c) env, err := environs.Prepare(cfg, ctx, configstore.NewMem()) c.Assert(err, gc.IsNil) envtesting.UploadFakeTools(c, env.Storage()) err = bootstrap.Bootstrap(ctx, env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // Check that Bootstrap has correctly used a hash // of the admin password. info, _, err := env.StateInfo() c.Assert(err, gc.IsNil) info.Password = utils.UserPasswordHash("nutkin", utils.CompatSalt) st, err := state.Open(info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) assertClose(c, st) // Check that we can connect with the original environment. conn, err := juju.NewConn(env) c.Assert(err, gc.IsNil) assertClose(c, conn) // Check that the password has now been changed to the original // admin password. info.Password = "******" st1, err := state.Open(info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) assertClose(c, st1) // Check that we can still connect with the original // environment. conn, err = juju.NewConn(env) c.Assert(err, gc.IsNil) defer assertClose(c, conn) // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, gc.IsNil) }
func (c *upgradeWorkerContext) run(stop <-chan struct{}) error { select { case <-c.UpgradeComplete: // Our work is already done (we're probably being restarted // because the API connection has gone down), so do nothing. return nil default: } agentConfig := c.agent.CurrentConfig() // If the machine agent is a state server, flag that state // needs to be opened before running upgrade steps needsState := false for _, job := range c.jobs { if job == params.JobManageEnviron { needsState = true } } // We need a *state.State for upgrades. We open it independently // of StateWorker, because we have no guarantees about when // and how often StateWorker might run. var st *state.State if needsState { if err := c.agent.ensureMongoServer(agentConfig); err != nil { return err } var err error info, ok := agentConfig.MongoInfo() if !ok { return fmt.Errorf("no state info available") } st, err = state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) if err != nil { return err } defer st.Close() } if err := c.runUpgrades(st, agentConfig); err != nil { // Only return an error from the worker if the connection to // state went away (possible mongo master change). Returning // an error when the connection is lost will cause the agent // to restart. // // For other errors, the error is not returned because we want // the machine agent to stay running in an error state waiting // for user intervention. if isAPILostDuringUpgrade(err) { return err } } else { // Upgrade succeeded - signal that the upgrade is complete. close(c.UpgradeComplete) } return nil }
func (s *BootstrapSuite) TestInitializeEnvironment(c *gc.C) { hw := instance.MustParseHardware("arch=amd64 mem=8G") machConf, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", s.envcfg, "--instance-id", string(s.instanceId), "--hardware", hw.String()) c.Assert(err, gc.IsNil) err = cmd.Run(nil) c.Assert(err, gc.IsNil) c.Assert(s.fakeEnsureMongo.dataDir, gc.Equals, s.dataDir) c.Assert(s.fakeEnsureMongo.initiateCount, gc.Equals, 1) c.Assert(s.fakeEnsureMongo.ensureCount, gc.Equals, 1) c.Assert(s.fakeEnsureMongo.dataDir, gc.Equals, s.dataDir) c.Assert(s.fakeEnsureMongo.oplogSize, gc.Equals, 1234) expectInfo, exists := machConf.StateServingInfo() c.Assert(exists, jc.IsTrue) c.Assert(expectInfo.SharedSecret, gc.Equals, "") servingInfo := s.fakeEnsureMongo.info c.Assert(len(servingInfo.SharedSecret), gc.Not(gc.Equals), 0) servingInfo.SharedSecret = "" c.Assert(servingInfo, jc.DeepEquals, expectInfo) expectDialAddrs := []string{fmt.Sprintf("127.0.0.1:%d", expectInfo.StatePort)} gotDialAddrs := s.fakeEnsureMongo.initiateParams.DialInfo.Addrs c.Assert(gotDialAddrs, gc.DeepEquals, expectDialAddrs) memberHost := fmt.Sprintf("%s:%d", s.bootstrapName, expectInfo.StatePort) c.Assert(s.fakeEnsureMongo.initiateParams.MemberHostPort, gc.Equals, memberHost) c.Assert(s.fakeEnsureMongo.initiateParams.User, gc.Equals, "") c.Assert(s.fakeEnsureMongo.initiateParams.Password, gc.Equals, "") st, err := state.Open(&authentication.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPasswordHash(), }, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() machines, err := st.AllMachines() c.Assert(err, gc.IsNil) c.Assert(machines, gc.HasLen, 1) instid, err := machines[0].InstanceId() c.Assert(err, gc.IsNil) c.Assert(instid, gc.Equals, instance.Id(string(s.instanceId))) stateHw, err := machines[0].HardwareCharacteristics() c.Assert(err, gc.IsNil) c.Assert(stateHw, gc.NotNil) c.Assert(*stateHw, gc.DeepEquals, hw) cons, err := st.EnvironConstraints() c.Assert(err, gc.IsNil) c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) }
func (s *BootstrapSuite) testToolsMetadata(c *gc.C, exploded bool) { envtesting.RemoveFakeToolsMetadata(c, s.toolsStorage) _, cmd, err := s.initBootstrapCommand(c, nil, "--model-config", s.b64yamlControllerModelConfig, "--hosted-model-config", s.b64yamlHostedModelConfig, "--instance-id", string(s.instanceId), ) c.Assert(err, jc.ErrorIsNil) err = cmd.Run(nil) c.Assert(err, jc.ErrorIsNil) // We don't write metadata at bootstrap anymore. simplestreamsMetadata, err := envtools.ReadMetadata(s.toolsStorage, "released") c.Assert(err, jc.ErrorIsNil) c.Assert(simplestreamsMetadata, gc.HasLen, 0) // The tools should have been added to tools storage, and // exploded into each of the supported series of // the same operating system if the tools were uploaded. st, err := state.Open(testing.ModelTag, &mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPassword, }, mongotest.DialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) defer st.Close() expectedSeries := make(set.Strings) if exploded { for _, ser := range series.SupportedSeries() { os, err := series.GetOSFromSeries(ser) c.Assert(err, jc.ErrorIsNil) hostos, err := series.GetOSFromSeries(series.HostSeries()) c.Assert(err, jc.ErrorIsNil) if os == hostos { expectedSeries.Add(ser) } } } else { expectedSeries.Add(series.HostSeries()) } storage, err := st.ToolsStorage() c.Assert(err, jc.ErrorIsNil) defer storage.Close() metadata, err := storage.AllMetadata() c.Assert(err, jc.ErrorIsNil) c.Assert(metadata, gc.HasLen, expectedSeries.Size()) for _, m := range metadata { v := version.MustParseBinary(m.Version) c.Assert(expectedSeries.Contains(v.Series), jc.IsTrue) } }
// newState returns a new State that uses the given environment. // The environment must have already been bootstrapped. func newState(environ environs.Environ, mongoInfo *authentication.MongoInfo) (*state.State, error) { password := environ.Config().AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } if err := environs.CheckEnvironment(environ); err != nil { return nil, err } mongoInfo.Password = password opts := mongo.DefaultDialOpts() st, err := state.Open(mongoInfo, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(err) { // We can't connect with the administrator password,; // perhaps this was the first connection and the // password has not been changed yet. mongoInfo.Password = utils.UserPasswordHash(password, utils.CompatSalt) // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(mongoInfo, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(err) { break } } if err != nil { return nil, err } if err := st.SetAdminMongoPassword(password); err != nil { return nil, err } } else if err != nil { return nil, err } if err := updateSecrets(environ, st); err != nil { st.Close() return nil, fmt.Errorf("unable to push secrets: %v", err) } return st, nil }
func testOpenState(c *gc.C, info *authentication.MongoInfo, expectErrType error) { st, err := state.Open(info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if st != nil { st.Close() } if expectErrType != nil { c.Assert(err, gc.FitsTypeOf, expectErrType) } else { c.Assert(err, gc.IsNil) } }
func testOpenState(c *gc.C, info *mongo.MongoInfo, expectErrType error) { st, err := state.Open(testing.EnvironmentTag, info, mongo.DefaultDialOpts(), environs.NewStatePolicy()) if st != nil { st.Close() } if expectErrType != nil { c.Assert(err, gc.FitsTypeOf, expectErrType) } else { c.Assert(err, jc.ErrorIsNil) } }
func (s *baseSuite) tryOpenState(c *gc.C, e apiAuthenticator, password string) error { stateInfo := s.MongoInfo(c) stateInfo.Tag = e.Tag() stateInfo.Password = password st, err := state.Open(s.State.EnvironTag(), stateInfo, mongo.DialOpts{ Timeout: 25 * time.Millisecond, }, environs.NewStatePolicy()) if err == nil { st.Close() } return err }
func (s *BootstrapSuite) testToolsMetadata(c *gc.C, exploded bool) { provider, err := environs.Provider(s.envcfg.Type()) c.Assert(err, gc.IsNil) env, err := provider.Open(s.envcfg) c.Assert(err, gc.IsNil) envtesting.RemoveFakeToolsMetadata(c, env.Storage()) _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", s.b64yamlEnvcfg, "--instance-id", string(s.instanceId)) c.Assert(err, gc.IsNil) err = cmd.Run(nil) c.Assert(err, gc.IsNil) // We don't write metadata at bootstrap anymore. simplestreamsMetadata, err := envtools.ReadMetadata(env.Storage()) c.Assert(err, gc.IsNil) c.Assert(simplestreamsMetadata, gc.HasLen, 0) // The tools should have been added to state, and // exploded into each of the supported series of // the same operating system if the tools were uploaded. st, err := state.Open(&mongo.MongoInfo{ Info: mongo.Info{ Addrs: []string{gitjujutesting.MgoServer.Addr()}, CACert: testing.CACert, }, Password: testPasswordHash(), }, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() var expectedSeries set.Strings if exploded { for _, series := range version.SupportedSeries() { os, err := version.GetOSFromSeries(series) c.Assert(err, gc.IsNil) if os == version.Current.OS { expectedSeries.Add(series) } } } else { expectedSeries.Add(version.Current.Series) } storage, err := st.ToolsStorage() c.Assert(err, gc.IsNil) defer storage.Close() metadata, err := storage.AllMetadata() c.Assert(err, gc.IsNil) c.Assert(metadata, gc.HasLen, expectedSeries.Size()) for _, m := range metadata { c.Assert(expectedSeries.Contains(m.Version.Series), jc.IsTrue) } }
// upgradeWorker runs the required upgrade operations to upgrade to the current Juju version. func (a *MachineAgent) upgradeWorker( apiState *api.State, jobs []params.MachineJob, agentConfig agent.Config, ) worker.Worker { return worker.NewSimpleWorker(func(stop <-chan struct{}) error { select { case <-a.upgradeComplete: // Our work is already done (we're probably being restarted // because the API connection has gone down), so do nothing. <-stop return nil default: } // If the machine agent is a state server, flag that state // needs to be opened before running upgrade steps needsState := false for _, job := range jobs { if job == params.JobManageEnviron { needsState = true } } // We need a *state.State for upgrades. We open it independently // of StateWorker, because we have no guarantees about when // and how often StateWorker might run. var st *state.State if needsState { if err := a.ensureMongoServer(agentConfig); err != nil { return err } var err error info, ok := agentConfig.StateInfo() if !ok { return fmt.Errorf("no state info available") } st, err = state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy()) if err != nil { return err } defer st.Close() } err := a.runUpgrades(st, apiState, jobs, agentConfig) if err != nil { return err } logger.Infof("upgrade to %v completed.", version.Current) close(a.upgradeComplete) <-stop return nil }) }
func (s *UpgradeSuite) SetUpTest(c *gc.C) { s.commonMachineSuite.SetUpTest(c) // clear s.aptCmds s.setAptCmds(nil) // Capture all apt commands. aptCmds := s.AgentSuite.HookCommandOutput(&pacman.CommandOutput, nil, nil) go func() { for cmd := range aptCmds { s.setAptCmds(cmd) } }() s.oldVersion = version.Binary{ Number: version.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } s.oldVersion.Major = 1 s.oldVersion.Minor = 16 // Don't wait so long in tests. s.PatchValue(&upgradeStartTimeoutMaster, time.Duration(time.Millisecond*50)) s.PatchValue(&upgradeStartTimeoutSecondary, time.Duration(time.Millisecond*60)) // Allow tests to make the API connection appear to be dead. s.connectionDead = false s.PatchValue(&cmdutil.ConnectionIsDead, func(loggo.Logger, cmdutil.Pinger) bool { return s.connectionDead }) var fakeOpenStateForUpgrade = func(upgradingMachineAgent, agent.Config) (*state.State, error) { mongoInfo := s.State.MongoConnectionInfo() st, err := state.Open(s.State.EnvironTag(), mongoInfo, mongo.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, jc.ErrorIsNil) return st, nil } s.PatchValue(&openStateForUpgrade, fakeOpenStateForUpgrade) s.machineIsMaster = true fakeIsMachineMaster := func(*state.State, string) (bool, error) { return s.machineIsMaster, nil } s.PatchValue(&isMachineMaster, fakeIsMachineMaster) // Most of these tests normally finish sub-second on a fast machine. // If any given test hits a minute, we have almost certainly become // wedged, so dump the logs. coretesting.DumpTestLogsAfter(time.Minute, c, s) }