// OpenState tries to open the state using the given Conf. If // passwordChanged is returned as true, c.StateInfo.Password has been // changed, and the caller should write the configuration // and set the entity's password accordingly (in that order). func (c *Conf) OpenState() (st *state.State, passwordChanged bool, err error) { info := *c.StateInfo if info.Password != "" { st, err := state.Open(&info) if err == nil { return st, false, nil } if err != state.ErrUnauthorized { return nil, false, err } // Access isn't authorized even though we have a password // This can happen if we crash after saving the // password but before changing it, so we'll try again // with the old password. } info.Password = c.OldPassword st, err = state.Open(&info) if err != nil { return nil, false, err } // We've succeeded in connecting with the old password, so // we can now change it to something more private. password, err := trivial.RandomPassword() if err != nil { st.Close() return nil, false, err } c.StateInfo.Password = password return st, true, nil }
func (s *BootstrapSuite) TestInitialPassword(c *C) { machineConf, cmd, err := s.initBootstrapCommand(c, "--env-config", testConfig) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) // Check that we cannot now connect to the state without a // password. info := &state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(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()) c.Assert(err, 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, IsNil) c.Assert(u.PasswordValid(testPassword), 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.ReadConf(machineConf.DataDir, "machine-0") c.Assert(err, IsNil) c.Assert(machineConf1.OldPassword, Equals, "") c.Assert(machineConf1.APIInfo.Password, Not(Equals), "") c.Assert(machineConf1.StateInfo.Password, Equals, machineConf1.APIInfo.Password) // Check that no other information has been lost. machineConf.OldPassword = "" machineConf.APIInfo.Password = machineConf1.APIInfo.Password machineConf.StateInfo.Password = machineConf1.StateInfo.Password c.Assert(machineConf1, DeepEquals, machineConf) info.Tag, info.Password = "******", machineConf1.StateInfo.Password st, err = state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, IsNil) c.Assert(m.PasswordValid(machineConf1.StateInfo.Password), Equals, true) }
func testSetMongoPassword(c *C, getEntity func(st *state.State) (entity, error)) { info := state.TestingStateInfo() st, err := state.Open(info) c.Assert(err, IsNil) defer st.Close() // Turn on fully-authenticated mode. err = st.SetAdminMongoPassword("admin-secret") c.Assert(err, IsNil) // Set the password for the entity ent, err := getEntity(st) c.Assert(err, IsNil) err = ent.SetMongoPassword("foo") c.Assert(err, IsNil) // Check that we cannot log in with the wrong password. info.EntityName = ent.EntityName() info.Password = "******" err = tryOpenState(info) c.Assert(err, Equals, state.ErrUnauthorized) // Check that we can log in with the correct password. info.Password = "******" st1, err := state.Open(info) c.Assert(err, IsNil) defer st1.Close() // Change the password with an entity derived from the newly // opened and authenticated state. ent, err = getEntity(st) c.Assert(err, IsNil) err = ent.SetMongoPassword("bar") c.Assert(err, IsNil) // Check that we cannot log in with the old password. info.Password = "******" err = tryOpenState(info) c.Assert(err, Equals, state.ErrUnauthorized) // Check that we can log in with the correct password. info.Password = "******" err = tryOpenState(info) c.Assert(err, IsNil) // Check that the administrator can still log in. info.EntityName, info.Password = "", "admin-secret" err = tryOpenState(info) c.Assert(err, IsNil) // Remove the admin password so that the test harness can reset the state. err = st.SetAdminMongoPassword("") c.Assert(err, IsNil) }
// 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) if errors.IsUnauthorizedError(err) { log.Noticef("juju: 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.PasswordHash(password) // 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) if !errors.IsUnauthorizedError(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) TestSetMachineId(c *C) { args := []string{ "--instance-id", "over9000", "--env-config", b64yaml{ "name": "dummyenv", "type": "dummy", "state-server": false, "authorized-keys": "i-am-a-key", "ca-cert": testing.CACert, }.encode(), } _, cmd, err := s.initBootstrapCommand(c, args...) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), }) c.Assert(err, IsNil) defer st.Close() machines, err := st.AllMachines() c.Assert(err, IsNil) c.Assert(len(machines), Equals, 1) instid, err := machines[0].InstanceId() c.Assert(err, IsNil) c.Assert(instid, Equals, state.InstanceId("over9000")) }
func (s *BootstrapSuite) TestMachinerWorkers(c *C) { args := []string{ "--instance-id", "over9000", "--env-config", b64yaml{ "name": "dummyenv", "type": "dummy", "state-server": false, "authorized-keys": "i-am-a-key", "ca-cert": testing.CACert, }.encode(), } _, cmd, err := s.initBootstrapCommand(c, args...) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), }) c.Assert(err, IsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, IsNil) c.Assert(m.Jobs(), DeepEquals, []state.MachineJob{state.JobManageEnviron}) }
func (s *BootstrapSuite) TestInitializeEnvironment(c *C) { _, cmd, err := s.initBootstrapCommand(c, "--env-config", testConfig) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), Password: testPasswordHash(), }, state.DefaultDialOpts()) c.Assert(err, IsNil) defer st.Close() machines, err := st.AllMachines() c.Assert(err, IsNil) c.Assert(machines, HasLen, 1) instid, err := machines[0].InstanceId() c.Assert(err, IsNil) c.Assert(instid, Equals, instance.Id("dummy.instance.id")) cons, err := st.EnvironConstraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, constraints.Value{}) }
func tryOpenState(info *state.Info) error { st, err := state.Open(info, state.DialOpts{}) if err == nil { st.Close() } return err }
func (s *InitializeSuite) SetUpTest(c *C) { s.LoggingSuite.SetUpTest(c) s.MgoSuite.SetUpTest(c) var err error s.State, err = state.Open(state.TestingStateInfo(), state.TestingDialOpts()) c.Assert(err, IsNil) }
func (s *BootstrapSuite) TestSetConstraints(c *C) { tcons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)} _, cmd, err := s.initBootstrapCommand(c, "--env-config", testConfig, "--constraints", tcons.String()) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), Password: testPasswordHash(), }, state.DefaultDialOpts()) c.Assert(err, IsNil) defer st.Close() cons, err := st.EnvironConstraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, tcons) machines, err := st.AllMachines() c.Assert(err, IsNil) c.Assert(machines, HasLen, 1) cons, err = machines[0].Constraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, tcons) }
func (s *suite) TestMachineSetPassword(c *C) { m, err := s.st.MachineAgent().Machine(s.machine.Tag()) c.Assert(err, IsNil) err = m.SetPassword("foo") c.Assert(err, IsNil) err = s.machine.Refresh() c.Assert(err, IsNil) c.Assert(s.machine.PasswordValid("bar"), Equals, false) c.Assert(s.machine.PasswordValid("foo"), Equals, true) // Check that we cannot log in to mongo with the wrong password. info := s.StateInfo(c) info.Tag = m.Tag() info.Password = "******" err = tryOpenState(info) c.Assert(err, checkers.Satisfies, errors.IsUnauthorizedError) // Check that we can log in with the correct password info.Password = "******" st, err := state.Open(info, state.DialOpts{}) c.Assert(err, IsNil) st.Close() }
// checkStartInstance checks that an instance has been started // with a machine id the same as m's, and that the machine's // instance id has been set appropriately. func (s *ProvisionerSuite) checkStartInstance(c *C, m *state.Machine, secret string) { s.State.StartSync() for { select { case o := <-s.op: switch o := o.(type) { case dummy.OpStartInstance: info := s.StateInfo(c) info.EntityName = m.EntityName() c.Assert(o.Info.Password, Not(HasLen), 0) info.Password = o.Info.Password c.Assert(o.Info, DeepEquals, info) // Check we can connect to the state with // the machine's entity name and password. st, err := state.Open(o.Info) c.Assert(err, IsNil) st.Close() c.Assert(o.MachineId, Equals, m.Id()) c.Assert(o.Instance, NotNil) s.checkInstanceId(c, m, o.Instance) c.Assert(o.Secret, Equals, secret) return default: c.Logf("ignoring unexpected operation %#v", o) } case <-time.After(2 * time.Second): c.Errorf("provisioner did not start an instance") return } } }
// OpenState tries to open the state using the given Conf. func (c *Conf) OpenState() (*state.State, error) { info := *c.StateInfo if info.Password != "" { st, err := state.Open(&info, state.DefaultDialOpts()) if err == nil { return st, nil } // TODO(rog) remove this fallback behaviour when // all initial connections are via the API. if !errors.IsUnauthorizedError(err) { return nil, err } } info.Password = c.OldPassword return state.Open(&info, state.DefaultDialOpts()) }
func (cs *NewConnSuite) TestConnWithPassword(c *C) { env, err := environs.NewFromAttrs(map[string]interface{}{ "name": "erewhemos", "type": "dummy", "state-server": true, "authorized-keys": "i-am-a-key", "secret": "squirrel", "admin-secret": "nutkin", "ca-cert": coretesting.CACert, "ca-private-key": coretesting.CAKey, }) c.Assert(err, IsNil) err = environs.Bootstrap(env, constraints.Value{}) c.Assert(err, IsNil) // Check that Bootstrap has correctly used a hash // of the admin password. info, _, err := env.StateInfo() c.Assert(err, IsNil) info.Password = utils.PasswordHash("nutkin") st, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) st.Close() // Check that we can connect with the original environment. conn, err := juju.NewConn(env) c.Assert(err, IsNil) conn.Close() // Check that the password has now been changed to the original // admin password. info.Password = "******" st1, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) st1.Close() // Check that we can still connect with the original // environment. conn, err = juju.NewConn(env) c.Assert(err, IsNil) defer conn.Close() // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, IsNil) }
func (s *StateSuite) TestDialAgain(c *C) { // Ensure idempotent operations on Dial are working fine. for i := 0; i < 2; i++ { st, err := state.Open(state.TestingStateInfo()) c.Assert(err, IsNil) c.Assert(st.Close(), IsNil) } }
// 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") } info.Password = password st, err := state.Open(info) if err == state.ErrUnauthorized { // We can't connect with the administrator password,; // perhaps this was the first connection and the // password has not been changed yet. info.Password = trivial.PasswordHash(password) // 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) if err != state.ErrUnauthorized { 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 testOpenState(c *C, info *state.Info, expectErr error) { st, err := state.Open(info) if st != nil { st.Close() } if expectErr != nil { c.Assert(err, Equals, expectErr) } else { c.Assert(err, IsNil) } }
func testOpenState(c *C, info *state.Info, expectErrType error) { st, err := state.Open(info, state.DefaultDialOpts()) if st != nil { st.Close() } if expectErrType != nil { c.Assert(err, FitsTypeOf, expectErrType) } else { c.Assert(err, IsNil) } }
func (cs *ConnSuite) SetUpTest(c *C) { cs.LoggingSuite.SetUpTest(c) cs.MgoSuite.SetUpTest(c) cs.charms = cs.MgoSuite.Session.DB("juju").C("charms") cs.machines = cs.MgoSuite.Session.DB("juju").C("machines") cs.relations = cs.MgoSuite.Session.DB("juju").C("relations") cs.services = cs.MgoSuite.Session.DB("juju").C("services") cs.units = cs.MgoSuite.Session.DB("juju").C("units") var err error cs.State, err = state.Open(state.TestingStateInfo()) c.Assert(err, IsNil) }
func (s *CommonProvisionerSuite) checkStartInstanceCustom(c *C, m *state.Machine, secret string, cons constraints.Value) (inst instance.Instance) { s.State.StartSync() for { select { case o := <-s.op: switch o := o.(type) { case dummy.OpStartInstance: inst = o.Instance s.waitInstanceId(c, m, inst.Id()) // Check the instance was started with the expected params. c.Assert(o.MachineId, Equals, m.Id()) nonceParts := strings.SplitN(o.MachineNonce, ":", 2) c.Assert(nonceParts, HasLen, 2) c.Assert(nonceParts[0], Equals, state.MachineTag("0")) c.Assert(nonceParts[1], checkers.Satisfies, utils.IsValidUUIDString) c.Assert(o.Secret, Equals, secret) c.Assert(o.Constraints, DeepEquals, cons) // Check we can connect to the state with // the machine's entity name and password. info := s.StateInfo(c) info.Tag = m.Tag() c.Assert(o.Info.Password, Not(HasLen), 0) info.Password = o.Info.Password c.Assert(o.Info, DeepEquals, info) // Check we can connect to the state with // the machine's entity name and password. st, err := state.Open(o.Info, state.DefaultDialOpts()) c.Assert(err, IsNil) // All provisioned machines in this test suite have their hardware characteristics // attributes set to the same values as the constraints due to the dummy environment being used. hc, err := m.HardwareCharacteristics() c.Assert(err, IsNil) c.Assert(*hc, DeepEquals, instance.HardwareCharacteristics{ Arch: cons.Arch, Mem: cons.Mem, CpuCores: cons.CpuCores, CpuPower: cons.CpuPower, }) st.Close() return default: c.Logf("ignoring unexpected operation %#v", o) } case <-time.After(2 * time.Second): c.Fatalf("provisioner did not start an instance") return } } return }
func (s *baseSuite) tryOpenState(c *C, e apiAuthenticator, password string) error { stateInfo := s.StateInfo(c) stateInfo.Tag = e.Tag() stateInfo.Password = password st, err := state.Open(stateInfo, state.DialOpts{ Timeout: 25 * time.Millisecond, }) if err == nil { st.Close() } return err }
func (s *BootstrapSuite) TestMachinerWorkers(c *C) { _, cmd, err := s.initBootstrapCommand(c, "--env-config", testConfig) c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) st, err := state.Open(&state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), Password: testPasswordHash(), }, state.DefaultDialOpts()) c.Assert(err, IsNil) defer st.Close() m, err := st.Machine("0") c.Assert(err, IsNil) c.Assert(m.Jobs(), DeepEquals, []state.MachineJob{ state.JobManageEnviron, state.JobManageState, state.JobHostUnits, }) }
func (s *ProvisionerSuite) checkStartInstanceCustom(c *C, m *state.Machine, secret string, cons constraints.Value) { s.State.StartSync() for { select { case o := <-s.op: switch o := o.(type) { case dummy.OpStartInstance: s.waitInstanceId(c, m, o.Instance.Id()) // Check the instance was started with the expected params. c.Assert(o.MachineId, Equals, m.Id()) nonceParts := strings.SplitN(o.MachineNonce, ":", 2) c.Assert(nonceParts, HasLen, 2) c.Assert(nonceParts[0], Equals, state.MachineTag("0")) c.Assert(utils.IsValidUUIDString(nonceParts[1]), Equals, true) c.Assert(o.Secret, Equals, secret) c.Assert(o.Constraints, DeepEquals, cons) // Check we can connect to the state with // the machine's entity name and password. info := s.StateInfo(c) info.Tag = m.Tag() c.Assert(o.Info.Password, Not(HasLen), 0) info.Password = o.Info.Password c.Assert(o.Info, DeepEquals, info) // Check we can connect to the state with // the machine's entity name and password. st, err := state.Open(o.Info, state.DefaultDialOpts()) c.Assert(err, IsNil) st.Close() return default: c.Logf("ignoring unexpected operation %#v", o) } case <-time.After(2 * time.Second): c.Fatalf("provisioner did not start an instance") return } } }
func (s *BootstrapSuite) TestInitialPassword(c *C) { args := []string{ "--instance-id", "over9000", "--env-config", b64yaml{ "name": "dummyenv", "type": "dummy", "state-server": false, "authorized-keys": "i-am-a-key", "ca-cert": testing.CACert, }.encode(), } conf, cmd, err := s.initBootstrapCommand(c, args...) c.Assert(err, IsNil) conf.OldPassword = "******" err = conf.Write() c.Assert(err, IsNil) err = cmd.Run(nil) c.Assert(err, IsNil) // Check that we cannot now connect to the state // without a password. info := &state.Info{ Addrs: []string{testing.MgoAddr}, CACert: []byte(testing.CACert), } testOpenState(c, info, state.ErrUnauthorized) info.EntityName, info.Password = "******", "foo" testOpenState(c, info, nil) info.EntityName = "" st, err := state.Open(info) c.Assert(err, IsNil) defer st.Close() // Reset password so the tests can continue to use the same server. err = st.SetAdminMongoPassword("") c.Assert(err, IsNil) }
func (cs *NewConnSuite) TestConnStateSecretsSideEffect(c *C) { attrs := map[string]interface{}{ "name": "erewhemos", "type": "dummy", "state-server": true, "authorized-keys": "i-am-a-key", "secret": "pork", "admin-secret": "side-effect secret", "ca-cert": coretesting.CACert, "ca-private-key": coretesting.CAKey, } env, err := environs.NewFromAttrs(attrs) c.Assert(err, IsNil) err = environs.Bootstrap(env, constraints.Value{}) c.Assert(err, IsNil) info, _, err := env.StateInfo() c.Assert(err, IsNil) info.Password = utils.PasswordHash("side-effect secret") st, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) // Verify we have no secret in the environ config cfg, err := st.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.UnknownAttrs()["secret"], IsNil) // Make a new Conn, which will push the secrets. conn, err := juju.NewConn(env) c.Assert(err, IsNil) defer conn.Close() cfg, err = conn.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.UnknownAttrs()["secret"], Equals, "pork") // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, IsNil) }
func (s *UnitSuite) TestSetMongoPasswordOnUnitAfterConnectingAsMachineEntity(c *C) { // Make a second unit to use later. (Subordinate units can only be created // as a side-effect of a principal entering relation scope.) subCharm := s.AddTestingCharm(c, "logging") _, err := s.State.AddService("logging", subCharm) c.Assert(err, IsNil) eps, err := s.State.InferEndpoints([]string{"wordpress", "logging"}) c.Assert(err, IsNil) rel, err := s.State.AddRelation(eps...) c.Assert(err, IsNil) ru, err := rel.Unit(s.unit) c.Assert(err, IsNil) err = ru.EnterScope(nil) c.Assert(err, IsNil) subUnit, err := s.State.Unit("logging/0") c.Assert(err, IsNil) info := state.TestingStateInfo() st, err := state.Open(info, state.TestingDialOpts()) c.Assert(err, IsNil) defer st.Close() // Turn on fully-authenticated mode. err = st.SetAdminMongoPassword("admin-secret") c.Assert(err, IsNil) // Add a new machine, assign the units to it // and set its password. m, err := st.AddMachine("series", state.JobHostUnits) c.Assert(err, IsNil) unit, err := st.Unit(s.unit.Name()) c.Assert(err, IsNil) subUnit, err = st.Unit(subUnit.Name()) c.Assert(err, IsNil) err = unit.AssignToMachine(m) c.Assert(err, IsNil) err = m.SetMongoPassword("foo") c.Assert(err, IsNil) // Sanity check that we cannot connect with the wrong // password info.Tag = m.Tag() info.Password = "******" err = tryOpenState(info) c.Assert(err, checkers.Satisfies, errors.IsUnauthorizedError) // Connect as the machine entity. info.Tag = m.Tag() info.Password = "******" st1, err := state.Open(info, state.TestingDialOpts()) c.Assert(err, IsNil) defer st1.Close() // Change the password for a unit derived from // the machine entity's state. unit, err = st1.Unit(s.unit.Name()) c.Assert(err, IsNil) err = unit.SetMongoPassword("bar") c.Assert(err, IsNil) // Now connect as the unit entity and, as that // that entity, change the password for a new unit. info.Tag = unit.Tag() info.Password = "******" st2, err := state.Open(info, state.TestingDialOpts()) c.Assert(err, IsNil) defer st2.Close() // Check that we can set its password. unit, err = st2.Unit(subUnit.Name()) c.Assert(err, IsNil) err = unit.SetMongoPassword("bar2") c.Assert(err, IsNil) // Clear the admin password, so tests can reset the db. err = st.SetAdminMongoPassword("") c.Assert(err, IsNil) }