github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/worker/peergrouper/initiate.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package peergrouper 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/utils" 11 "labix.org/v2/mgo" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/agent/mongo" 15 "github.com/juju/juju/replicaset" 16 ) 17 18 var initiateAttemptStrategy = utils.AttemptStrategy{ 19 Total: 30 * time.Second, 20 Delay: 1 * time.Second, 21 } 22 23 // InitiateMongoParams holds parameters for the MaybeInitiateMongo call. 24 type InitiateMongoParams struct { 25 // DialInfo specifies how to connect to the mongo server. 26 DialInfo *mgo.DialInfo 27 28 // MemberHostPort provides the address to use for 29 // the first replica set member. 30 MemberHostPort string 31 32 // User holds the user to log as in to the mongo server. 33 // If it is empty, no login will take place. 34 User string 35 Password string 36 } 37 38 // MaybeInitiateMongoServer checks for an existing mongo configuration. 39 // If no existing configuration is found one is created using Initiate. 40 func MaybeInitiateMongoServer(p InitiateMongoParams) error { 41 logger.Debugf("Initiating mongo replicaset; dialInfo %#v; memberHostport %q; user %q; password %q", p.DialInfo, p.MemberHostPort, p.User, p.Password) 42 defer logger.Infof("finished MaybeInitiateMongoServer") 43 44 if len(p.DialInfo.Addrs) > 1 { 45 logger.Infof("more than one member; replica set must be already initiated") 46 return nil 47 } 48 p.DialInfo.Direct = true 49 50 // TODO(rog) remove this code when we no longer need to upgrade 51 // from pre-HA-capable environments. 52 if p.User != "" { 53 p.DialInfo.Username = p.User 54 p.DialInfo.Password = p.Password 55 } 56 57 session, err := mgo.DialWithInfo(p.DialInfo) 58 if err != nil { 59 return fmt.Errorf("can't dial mongo to initiate replicaset: %v", err) 60 } 61 defer session.Close() 62 63 // Initiate may fail while mongo is initialising, so we retry until 64 // we succssfully populate the replicaset config. 65 for attempt := initiateAttemptStrategy.Start(); attempt.Next(); { 66 var cfg *replicaset.Config 67 cfg, err = replicaset.CurrentConfig(session) 68 if err == nil && len(cfg.Members) > 0 { 69 logger.Infof("replica set configuration already found: %#v", cfg) 70 return nil 71 } 72 if err != nil && err != mgo.ErrNotFound { 73 return fmt.Errorf("cannot get replica set configuration: %v", err) 74 } 75 err = replicaset.Initiate( 76 session, 77 p.MemberHostPort, 78 mongo.ReplicaSetName, 79 map[string]string{ 80 jujuMachineTag: agent.BootstrapMachineId, 81 }, 82 ) 83 if err == nil { 84 logger.Infof("replica set initiated") 85 return nil 86 } 87 if attempt.HasNext() { 88 logger.Debugf("replica set initiation failed, will retry: %v", err) 89 } 90 // Release sockets, which may have been closed by mgo. 91 session.Refresh() 92 } 93 return fmt.Errorf("cannot initiate replica set: %v", err) 94 }