// 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 := state.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) TestSetConstraints(c *gc.C) { tcons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)} _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", s.envcfg, "--instance-id", string(s.instanceId), "--constraints", tcons.String(), ) c.Assert(err, gc.IsNil) err = cmd.Run(nil) c.Assert(err, gc.IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, Password: testPasswordHash(), }, state.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() cons, err := st.EnvironConstraints() c.Assert(err, gc.IsNil) c.Assert(cons, gc.DeepEquals, tcons) machines, err := st.AllMachines() c.Assert(err, gc.IsNil) c.Assert(machines, gc.HasLen, 1) cons, err = machines[0].Constraints() c.Assert(err, gc.IsNil) c.Assert(cons, gc.DeepEquals, tcons) }
func tryOpenState(info *state.Info) error { st, err := state.Open(info, state.DialOpts{}, environs.NewStatePolicy()) if err == nil { st.Close() } return err }
func openState(agentConfig agent.Config) (_ *state.State, _ *state.Machine, err error) { info, ok := agentConfig.StateInfo() if !ok { return nil, nil, fmt.Errorf("no state info available") } st, err := state.Open(info, state.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) 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 := &state.Info{ Addrs: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, } testOpenState(c, info, errors.Unauthorizedf("")) // Check we can log in to mongo as admin. info.Tag, info.Password = "", testPasswordHash() st, err := state.Open(info, state.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(), "machine-0")) c.Assert(err, gc.IsNil) stateinfo, ok := machineConf1.StateInfo() c.Assert(ok, jc.IsTrue) st, err = state.Open(stateinfo, state.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 *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, state.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) st.Close() }
func testOpenState(c *gc.C, info *state.Info, expectErrType error) { st, err := state.Open(info, state.DefaultDialOpts(), environs.NewStatePolicy()) if st != nil { st.Close() } if expectErrType != nil { c.Assert(err, gc.FitsTypeOf, expectErrType) } else { c.Assert(err, gc.IsNil) } }
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) 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(&state.Info{ Addrs: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, Password: testPasswordHash(), }, state.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) }
// Reset resets the entire dummy environment and forgets any registered // operation listener. All opened environments after Reset will share // the same underlying state. func Reset() { logger.Infof("reset environment") p := &providerInstance p.mu.Lock() defer p.mu.Unlock() providerInstance.ops = discardOperations for _, s := range p.state { s.httpListener.Close() s.destroy() } providerInstance.state = make(map[int]*environState) if mongoAlive() { testing.MgoServer.Reset() } providerInstance.statePolicy = environs.NewStatePolicy() }
// 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, wait until state is opened. 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 { var err error info, ok := agentConfig.StateInfo() if !ok { return fmt.Errorf("no state info available") } st, err = state.Open(info, state.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 *BootstrapSuite) TestConfiguredMachineJobs(c *gc.C) { jobs := []params.MachineJob{params.JobManageEnviron} _, cmd, err := s.initBootstrapCommand(c, jobs, "--env-config", s.envcfg, "--instance-id", string(s.instanceId)) c.Assert(err, gc.IsNil) err = cmd.Run(nil) c.Assert(err, gc.IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, Password: testPasswordHash(), }, state.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, gc.IsNil) c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageEnviron}) }
// Run initializes state for an environment. func (c *BootstrapCommand) Run(_ *cmd.Context) error { envCfg, err := config.New(config.NoDefaults, c.EnvConfig) if err != nil { return err } err = c.ReadConfig("machine-0") if err != nil { return err } agentConfig := c.CurrentConfig() // agent.Jobs is an optional field in the agent config, and was // introduced after 1.17.2. We default to allowing units on // machine-0 if missing. jobs := agentConfig.Jobs() if len(jobs) == 0 { jobs = []params.MachineJob{ params.JobManageEnviron, params.JobHostUnits, } } // Get the bootstrap machine's addresses from the provider. env, err := environs.New(envCfg) if err != nil { return err } instanceId := instance.Id(c.InstanceId) instances, err := env.Instances([]instance.Id{instanceId}) if err != nil { return err } addrs, err := instances[0].Addresses() if err != nil { return err } // Create system-identity file if err := agent.WriteSystemIdentityFile(agentConfig); err != nil { return err } // Generate a shared secret for the Mongo replica set, and write it out. sharedSecret, err := mongo.GenerateSharedSecret() if err != nil { return err } info, ok := agentConfig.StateServingInfo() if !ok { return fmt.Errorf("bootstrap machine config has no state serving info") } info.SharedSecret = sharedSecret err = c.ChangeConfig(func(agentConfig agent.ConfigSetter) { agentConfig.SetStateServingInfo(info) }) if err != nil { return fmt.Errorf("cannot write agent config: %v", err) } agentConfig = c.CurrentConfig() if err := c.startMongo(addrs, agentConfig); err != nil { return err } logger.Infof("started mongo") // Initialise state, and store any agent config (e.g. password) changes. var st *state.State var m *state.Machine err = nil writeErr := c.ChangeConfig(func(agentConfig agent.ConfigSetter) { st, m, err = agent.InitializeState( agentConfig, envCfg, agent.BootstrapMachineConfig{ Addresses: addrs, Constraints: c.Constraints, Jobs: jobs, InstanceId: instanceId, Characteristics: c.Hardware, SharedSecret: sharedSecret, }, state.DefaultDialOpts(), environs.NewStatePolicy(), ) }) if writeErr != nil { return fmt.Errorf("cannot write initial configuration: %v", err) } if err != nil { return err } defer st.Close() // bootstrap machine always gets the vote return m.SetHasVote(true) }