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  }