github.com/clly/consul@v1.4.5/agent/consul/client_serf.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/consul/agent/metadata"
     9  	"github.com/hashicorp/consul/agent/structs"
    10  	"github.com/hashicorp/consul/lib"
    11  	"github.com/hashicorp/serf/serf"
    12  )
    13  
    14  // setupSerf is used to setup and initialize a Serf
    15  func (c *Client) setupSerf(conf *serf.Config, ch chan serf.Event, path string) (*serf.Serf, error) {
    16  	conf.Init()
    17  
    18  	conf.NodeName = c.config.NodeName
    19  	conf.Tags["role"] = "node"
    20  	conf.Tags["dc"] = c.config.Datacenter
    21  	conf.Tags["segment"] = c.config.Segment
    22  	conf.Tags["id"] = string(c.config.NodeID)
    23  	conf.Tags["vsn"] = fmt.Sprintf("%d", c.config.ProtocolVersion)
    24  	conf.Tags["vsn_min"] = fmt.Sprintf("%d", ProtocolVersionMin)
    25  	conf.Tags["vsn_max"] = fmt.Sprintf("%d", ProtocolVersionMax)
    26  	conf.Tags["build"] = c.config.Build
    27  	if c.acls.ACLsEnabled() {
    28  		// we start in legacy mode and then transition to normal
    29  		// mode once we know the cluster can handle it.
    30  		conf.Tags["acls"] = string(structs.ACLModeLegacy)
    31  	} else {
    32  		conf.Tags["acls"] = string(structs.ACLModeDisabled)
    33  	}
    34  
    35  	if c.logger == nil {
    36  		conf.MemberlistConfig.LogOutput = c.config.LogOutput
    37  		conf.LogOutput = c.config.LogOutput
    38  	}
    39  	conf.MemberlistConfig.Logger = c.logger
    40  	conf.Logger = c.logger
    41  	conf.EventCh = ch
    42  	conf.ProtocolVersion = protocolVersionMap[c.config.ProtocolVersion]
    43  	conf.RejoinAfterLeave = c.config.RejoinAfterLeave
    44  	conf.Merge = &lanMergeDelegate{
    45  		dc:       c.config.Datacenter,
    46  		nodeID:   c.config.NodeID,
    47  		nodeName: c.config.NodeName,
    48  		segment:  c.config.Segment,
    49  	}
    50  
    51  	conf.SnapshotPath = filepath.Join(c.config.DataDir, path)
    52  	if err := lib.EnsurePath(conf.SnapshotPath, false); err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	return serf.Create(conf)
    57  }
    58  
    59  // lanEventHandler is used to handle events from the lan Serf cluster
    60  func (c *Client) lanEventHandler() {
    61  	var numQueuedEvents int
    62  	for {
    63  		numQueuedEvents = len(c.eventCh)
    64  		if numQueuedEvents > serfEventBacklogWarning {
    65  			c.logger.Printf("[WARN] consul: number of queued serf events above warning threshold: %d/%d", numQueuedEvents, serfEventBacklogWarning)
    66  		}
    67  
    68  		select {
    69  		case e := <-c.eventCh:
    70  			switch e.EventType() {
    71  			case serf.EventMemberJoin:
    72  				c.nodeJoin(e.(serf.MemberEvent))
    73  			case serf.EventMemberLeave, serf.EventMemberFailed, serf.EventMemberReap:
    74  				c.nodeFail(e.(serf.MemberEvent))
    75  			case serf.EventUser:
    76  				c.localEvent(e.(serf.UserEvent))
    77  			case serf.EventMemberUpdate: // Ignore
    78  			case serf.EventQuery: // Ignore
    79  			default:
    80  				c.logger.Printf("[WARN] consul: unhandled LAN Serf Event: %#v", e)
    81  			}
    82  		case <-c.shutdownCh:
    83  			return
    84  		}
    85  	}
    86  }
    87  
    88  // nodeJoin is used to handle join events on the serf cluster
    89  func (c *Client) nodeJoin(me serf.MemberEvent) {
    90  	for _, m := range me.Members {
    91  		ok, parts := metadata.IsConsulServer(m)
    92  		if !ok {
    93  			continue
    94  		}
    95  		if parts.Datacenter != c.config.Datacenter {
    96  			c.logger.Printf("[WARN] consul: server %s for datacenter %s has joined wrong cluster",
    97  				m.Name, parts.Datacenter)
    98  			continue
    99  		}
   100  		c.logger.Printf("[INFO] consul: adding server %s", parts)
   101  		c.routers.AddServer(parts)
   102  
   103  		// Trigger the callback
   104  		if c.config.ServerUp != nil {
   105  			c.config.ServerUp()
   106  		}
   107  	}
   108  }
   109  
   110  // nodeFail is used to handle fail events on the serf cluster
   111  func (c *Client) nodeFail(me serf.MemberEvent) {
   112  	for _, m := range me.Members {
   113  		ok, parts := metadata.IsConsulServer(m)
   114  		if !ok {
   115  			continue
   116  		}
   117  		c.logger.Printf("[INFO] consul: removing server %s", parts)
   118  		c.routers.RemoveServer(parts)
   119  	}
   120  }
   121  
   122  // localEvent is called when we receive an event on the local Serf
   123  func (c *Client) localEvent(event serf.UserEvent) {
   124  	// Handle only consul events
   125  	if !strings.HasPrefix(event.Name, "consul:") {
   126  		return
   127  	}
   128  
   129  	switch name := event.Name; {
   130  	case name == newLeaderEvent:
   131  		c.logger.Printf("[INFO] consul: New leader elected: %s", event.Payload)
   132  
   133  		// Trigger the callback
   134  		if c.config.ServerUp != nil {
   135  			c.config.ServerUp()
   136  		}
   137  	case isUserEvent(name):
   138  		event.Name = rawUserEventName(name)
   139  		c.logger.Printf("[DEBUG] consul: user event: %s", event.Name)
   140  
   141  		// Trigger the callback
   142  		if c.config.UserEventHandler != nil {
   143  			c.config.UserEventHandler(event)
   144  		}
   145  	default:
   146  		if !c.handleEnterpriseUserEvents(event) {
   147  			c.logger.Printf("[WARN] consul: Unhandled local event: %v", event)
   148  		}
   149  	}
   150  }