// Open connects to the server described by the given // info, waits for it to be initialized, and returns a new State // representing the environment connected to. // // A policy may be provided, which will be used to validate and // modify behaviour of certain operations in state. A nil policy // may be provided. // // Open returns unauthorizedError if access is unauthorized. func Open(info *Info, opts mongo.DialOpts, policy Policy) (*State, error) { logger.Infof("opening state, mongo addresses: %q; entity %q", info.Addrs, info.Tag) di, err := mongo.DialInfo(info.Info, opts) if err != nil { return nil, err } logger.Debugf("dialing mongo") session, err := mgo.DialWithInfo(di) if err != nil { return nil, err } logger.Debugf("connection established") _, err = replicaset.CurrentConfig(session) safe := &mgo.Safe{J: true} if err == nil { // set mongo to write-majority (writes only returned after replicated // to a majority of replica-set members) safe.WMode = "majority" } session.SetSafe(safe) st, err := newState(session, info, policy) if err != nil { session.Close() return nil, err } session.SetSocketTimeout(mongo.SocketTimeout) return st, nil }
// attemptInitiateMongoServer attempts to initiate the replica set. func attemptInitiateMongoServer(dialInfo *mgo.DialInfo, memberHostPort string) error { session, err := mgo.DialWithInfo(dialInfo) if err != nil { return fmt.Errorf("can't dial mongo to initiate replicaset: %v", err) } defer session.Close() session.SetSocketTimeout(mongo.SocketTimeout) var cfg *replicaset.Config cfg, err = replicaset.CurrentConfig(session) if err == nil && len(cfg.Members) > 0 { logger.Infof("replica set configuration already found: %#v", cfg) return nil } if err != nil && err != mgo.ErrNotFound { return fmt.Errorf("cannot get replica set configuration: %v", err) } return replicaset.Initiate( session, memberHostPort, mongo.ReplicaSetName, map[string]string{ jujuMachineTag: agent.BootstrapMachineId, }, ) }
// MaybeInitiateMongoServer checks for an existing mongo configuration. // If no existing configuration is found one is created using Initiate. func MaybeInitiateMongoServer(p InitiateMongoParams) error { logger.Debugf("Initiating mongo replicaset; dialInfo %#v; memberHostport %q; user %q; password %q", p.DialInfo, p.MemberHostPort, p.User, p.Password) defer logger.Infof("finished MaybeInitiateMongoServer") if len(p.DialInfo.Addrs) > 1 { logger.Infof("more than one member; replica set must be already initiated") return nil } p.DialInfo.Direct = true // TODO(rog) remove this code when we no longer need to upgrade // from pre-HA-capable environments. if p.User != "" { p.DialInfo.Username = p.User p.DialInfo.Password = p.Password } session, err := mgo.DialWithInfo(p.DialInfo) if err != nil { return fmt.Errorf("can't dial mongo to initiate replicaset: %v", err) } defer session.Close() // Initiate may fail while mongo is initialising, so we retry until // we succssfully populate the replicaset config. for attempt := initiateAttemptStrategy.Start(); attempt.Next(); { var cfg *replicaset.Config cfg, err = replicaset.CurrentConfig(session) if err == nil && len(cfg.Members) > 0 { logger.Infof("replica set configuration already found: %#v", cfg) return nil } if err != nil && err != mgo.ErrNotFound { return fmt.Errorf("cannot get replica set configuration: %v", err) } err = replicaset.Initiate( session, p.MemberHostPort, mongo.ReplicaSetName, map[string]string{ jujuMachineTag: agent.BootstrapMachineId, }, ) if err == nil { logger.Infof("replica set initiated") return nil } if attempt.HasNext() { logger.Debugf("replica set initiation failed, will retry: %v", err) } // Release sockets, which may have been closed by mgo. session.Refresh() } return fmt.Errorf("cannot initiate replica set: %v", err) }
func init() { stateWorkerDialOpts = mongo.DefaultDialOpts() stateWorkerDialOpts.PostDial = func(session *mgo.Session) error { safe := mgo.Safe{ // Wait for group commit if journaling is enabled, // which is always true in production. J: true, } _, err := replicaset.CurrentConfig(session) if err == nil { // set mongo to write-majority (writes only returned after // replicated to a majority of replica-set members). safe.WMode = "majority" } session.SetSafe(&safe) return nil } }