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  }