github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/client/fingerprint/consul.go (about) 1 package fingerprint 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 "time" 8 9 consul "github.com/hashicorp/consul/api" 10 11 client "github.com/hashicorp/nomad/client/config" 12 "github.com/hashicorp/nomad/nomad/structs" 13 ) 14 15 const ( 16 consulAvailable = "available" 17 consulUnavailable = "unavailable" 18 ) 19 20 // ConsulFingerprint is used to fingerprint for Consul 21 type ConsulFingerprint struct { 22 logger *log.Logger 23 client *consul.Client 24 lastState string 25 } 26 27 // NewConsulFingerprint is used to create a Consul fingerprint 28 func NewConsulFingerprint(logger *log.Logger) Fingerprint { 29 return &ConsulFingerprint{logger: logger, lastState: consulUnavailable} 30 } 31 32 func (f *ConsulFingerprint) Fingerprint(config *client.Config, node *structs.Node) (bool, error) { 33 // Guard against uninitialized Links 34 if node.Links == nil { 35 node.Links = map[string]string{} 36 } 37 38 // Only create the client once to avoid creating too many connections to 39 // Consul. 40 if f.client == nil { 41 consulConfig, err := config.ConsulConfig.ApiConfig() 42 if err != nil { 43 return false, fmt.Errorf("Failed to initialize the Consul client config: %v", err) 44 } 45 46 f.client, err = consul.NewClient(consulConfig) 47 if err != nil { 48 return false, fmt.Errorf("Failed to initialize consul client: %s", err) 49 } 50 } 51 52 // We'll try to detect consul by making a query to to the agent's self API. 53 // If we can't hit this URL consul is probably not running on this machine. 54 info, err := f.client.Agent().Self() 55 if err != nil { 56 // Clear any attributes set by a previous fingerprint. 57 f.clearConsulAttributes(node) 58 59 // Print a message indicating that the Consul Agent is not available 60 // anymore 61 if f.lastState == consulAvailable { 62 f.logger.Printf("[INFO] fingerprint.consul: consul agent is unavailable") 63 } 64 f.lastState = consulUnavailable 65 return false, nil 66 } 67 68 if s, ok := info["Config"]["Server"].(bool); ok { 69 node.Attributes["consul.server"] = strconv.FormatBool(s) 70 } else { 71 f.logger.Printf("[WARN] fingerprint.consul: unable to fingerprint consul.server") 72 } 73 if v, ok := info["Config"]["Version"].(string); ok { 74 node.Attributes["consul.version"] = v 75 } else { 76 f.logger.Printf("[WARN] fingerprint.consul: unable to fingerprint consul.version") 77 } 78 if r, ok := info["Config"]["Revision"].(string); ok { 79 node.Attributes["consul.revision"] = r 80 } else { 81 f.logger.Printf("[WARN] fingerprint.consul: unable to fingerprint consul.revision") 82 } 83 if n, ok := info["Config"]["NodeName"].(string); ok { 84 node.Attributes["unique.consul.name"] = n 85 } else { 86 f.logger.Printf("[WARN] fingerprint.consul: unable to fingerprint unique.consul.name") 87 } 88 if d, ok := info["Config"]["Datacenter"].(string); ok { 89 node.Attributes["consul.datacenter"] = d 90 } else { 91 f.logger.Printf("[WARN] fingerprint.consul: unable to fingerprint consul.datacenter") 92 } 93 94 if node.Attributes["consul.datacenter"] != "" || node.Attributes["unique.consul.name"] != "" { 95 node.Links["consul"] = fmt.Sprintf("%s.%s", 96 node.Attributes["consul.datacenter"], 97 node.Attributes["unique.consul.name"]) 98 } else { 99 f.logger.Printf("[WARN] fingerprint.consul: malformed Consul response prevented linking") 100 } 101 102 // If the Consul Agent was previously unavailable print a message to 103 // indicate the Agent is available now 104 if f.lastState == consulUnavailable { 105 f.logger.Printf("[INFO] fingerprint.consul: consul agent is available") 106 } 107 f.lastState = consulAvailable 108 return true, nil 109 } 110 111 // clearConsulAttributes removes consul attributes and links from the passed 112 // Node. 113 func (f *ConsulFingerprint) clearConsulAttributes(n *structs.Node) { 114 delete(n.Attributes, "consul.server") 115 delete(n.Attributes, "consul.version") 116 delete(n.Attributes, "consul.revision") 117 delete(n.Attributes, "unique.consul.name") 118 delete(n.Attributes, "consul.datacenter") 119 delete(n.Links, "consul") 120 } 121 122 func (f *ConsulFingerprint) Periodic() (bool, time.Duration) { 123 return true, 15 * time.Second 124 }