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 }