github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/agent/retry_join.go (about)

     1  package agent
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/hashicorp/consul/lib"
    10  	discover "github.com/hashicorp/go-discover"
    11  	discoverk8s "github.com/hashicorp/go-discover/provider/k8s"
    12  )
    13  
    14  func (a *Agent) retryJoinLAN() {
    15  	r := &retryJoiner{
    16  		cluster:     "LAN",
    17  		addrs:       a.config.RetryJoinLAN,
    18  		maxAttempts: a.config.RetryJoinMaxAttemptsLAN,
    19  		interval:    a.config.RetryJoinIntervalLAN,
    20  		join:        a.JoinLAN,
    21  		logger:      a.logger,
    22  	}
    23  	if err := r.retryJoin(); err != nil {
    24  		a.retryJoinCh <- err
    25  	}
    26  }
    27  
    28  func (a *Agent) retryJoinWAN() {
    29  	r := &retryJoiner{
    30  		cluster:     "WAN",
    31  		addrs:       a.config.RetryJoinWAN,
    32  		maxAttempts: a.config.RetryJoinMaxAttemptsWAN,
    33  		interval:    a.config.RetryJoinIntervalWAN,
    34  		join:        a.JoinWAN,
    35  		logger:      a.logger,
    36  	}
    37  	if err := r.retryJoin(); err != nil {
    38  		a.retryJoinCh <- err
    39  	}
    40  }
    41  
    42  // retryJoiner is used to handle retrying a join until it succeeds or all
    43  // retries are exhausted.
    44  type retryJoiner struct {
    45  	// cluster is the name of the serf cluster, e.g. "LAN" or "WAN".
    46  	cluster string
    47  
    48  	// addrs is the list of servers or go-discover configurations
    49  	// to join with.
    50  	addrs []string
    51  
    52  	// maxAttempts is the number of join attempts before giving up.
    53  	maxAttempts int
    54  
    55  	// interval is the time between two join attempts.
    56  	interval time.Duration
    57  
    58  	// join adds the discovered or configured servers to the given
    59  	// serf cluster.
    60  	join func([]string) (int, error)
    61  
    62  	// logger is the agent logger. Log messages should contain the
    63  	// "agent: " prefix.
    64  	logger *log.Logger
    65  }
    66  
    67  func (r *retryJoiner) retryJoin() error {
    68  	if len(r.addrs) == 0 {
    69  		return nil
    70  	}
    71  
    72  	// Copy the default providers, and then add the non-default
    73  	providers := make(map[string]discover.Provider)
    74  	for k, v := range discover.Providers {
    75  		providers[k] = v
    76  	}
    77  	providers["k8s"] = &discoverk8s.Provider{}
    78  
    79  	disco, err := discover.New(
    80  		discover.WithUserAgent(lib.UserAgent()),
    81  		discover.WithProviders(providers),
    82  	)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	r.logger.Printf("[INFO] agent: Retry join %s is supported for: %s", r.cluster, strings.Join(disco.Names(), " "))
    88  	r.logger.Printf("[INFO] agent: Joining %s cluster...", r.cluster)
    89  	attempt := 0
    90  	for {
    91  		var addrs []string
    92  		var err error
    93  
    94  		for _, addr := range r.addrs {
    95  			switch {
    96  			case strings.Contains(addr, "provider="):
    97  				servers, err := disco.Addrs(addr, r.logger)
    98  				if err != nil {
    99  					r.logger.Printf("[ERR] agent: Join %s: %s", r.cluster, err)
   100  				} else {
   101  					addrs = append(addrs, servers...)
   102  					r.logger.Printf("[INFO] agent: Discovered %s servers: %s", r.cluster, strings.Join(servers, " "))
   103  				}
   104  
   105  			default:
   106  				addrs = append(addrs, addr)
   107  			}
   108  		}
   109  
   110  		if len(addrs) > 0 {
   111  			n, err := r.join(addrs)
   112  			if err == nil {
   113  				r.logger.Printf("[INFO] agent: Join %s completed. Synced with %d initial agents", r.cluster, n)
   114  				return nil
   115  			}
   116  		}
   117  
   118  		if len(addrs) == 0 {
   119  			err = fmt.Errorf("No servers to join")
   120  		}
   121  
   122  		attempt++
   123  		if r.maxAttempts > 0 && attempt > r.maxAttempts {
   124  			return fmt.Errorf("agent: max join %s retry exhausted, exiting", r.cluster)
   125  		}
   126  
   127  		r.logger.Printf("[WARN] agent: Join %s failed: %v, retrying in %v", r.cluster, err, r.interval)
   128  		time.Sleep(r.interval)
   129  	}
   130  }