github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/mgo/v3"
    12  	"github.com/juju/replicaset/v3"
    13  	"github.com/juju/retry"
    14  
    15  	"github.com/juju/juju/agent"
    16  	"github.com/juju/juju/mongo"
    17  )
    18  
    19  // InitiateMongoParams holds parameters for the MaybeInitiateMongo call.
    20  type InitiateMongoParams struct {
    21  	// DialInfo specifies how to connect to the mongo server.
    22  	DialInfo *mgo.DialInfo
    23  
    24  	// MemberHostPort provides the address to use for
    25  	// the first replica set member.
    26  	MemberHostPort string
    27  
    28  	// User holds the user to log as in to the mongo server.
    29  	// If it is empty, no login will take place.
    30  	User     string
    31  	Password string
    32  }
    33  
    34  // InitiateMongoServer checks for an existing mongo configuration.
    35  // If no existing configuration is found one is created using Initiate.
    36  func InitiateMongoServer(p InitiateMongoParams) error {
    37  	logger.Debugf("Initiating mongo replicaset; dialInfo %#v; memberHostport %q; user %q; password %q", p.DialInfo, p.MemberHostPort, p.User, p.Password)
    38  	defer logger.Infof("finished InitiateMongoServer")
    39  
    40  	if len(p.DialInfo.Addrs) > 1 {
    41  		logger.Infof("more than one member; replica set must be already initiated")
    42  		return nil
    43  	}
    44  	p.DialInfo.Direct = true
    45  
    46  	// Initiate may fail while mongo is initialising, so we retry until
    47  	// we successfully populate the replicaset config.
    48  	retryCallArgs := retry.CallArgs{
    49  		Clock:       clock.WallClock,
    50  		MaxDuration: 60 * time.Second,
    51  		Delay:       5 * time.Second,
    52  		Func: func() error {
    53  			return attemptInitiateMongoServer(p.DialInfo, p.MemberHostPort)
    54  		},
    55  		NotifyFunc: func(lastError error, attempt int) {
    56  			logger.Debugf("replica set initiation attempt %d failed: %v", attempt, lastError)
    57  		},
    58  	}
    59  	err := retry.Call(retryCallArgs)
    60  	if retry.IsAttemptsExceeded(err) || retry.IsDurationExceeded(err) {
    61  		err = retry.LastError(err)
    62  		logger.Debugf("replica set initiation failed: %v", err)
    63  	}
    64  	if err == nil {
    65  		logger.Infof("replica set initiated")
    66  		return nil
    67  	}
    68  	return errors.Annotatef(err, "cannot initiate replica set")
    69  }
    70  
    71  // attemptInitiateMongoServer attempts to initiate the replica set.
    72  func attemptInitiateMongoServer(dialInfo *mgo.DialInfo, memberHostPort string) error {
    73  	session, err := mgo.DialWithInfo(dialInfo)
    74  	if err != nil {
    75  		return errors.Annotatef(err, "cannot dial mongo to initiate replicaset")
    76  	}
    77  	defer session.Close()
    78  	session.SetSocketTimeout(mongo.SocketTimeout)
    79  
    80  	return replicaset.Initiate(
    81  		session,
    82  		memberHostPort,
    83  		mongo.ReplicaSetName,
    84  		map[string]string{
    85  			jujuNodeKey: agent.BootstrapControllerId,
    86  		},
    87  	)
    88  }