github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/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 the architecture
    21  type ConsulFingerprint struct {
    22  	logger    *log.Logger
    23  	client    *consul.Client
    24  	lastState string
    25  }
    26  
    27  // NewConsulFingerprint is used to create an OS 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  		address := config.ReadDefault("consul.address", "127.0.0.1:8500")
    42  		timeout, err := time.ParseDuration(config.ReadDefault("consul.timeout", "10ms"))
    43  		if err != nil {
    44  			return false, fmt.Errorf("Unable to parse consul.timeout: %s", err)
    45  		}
    46  
    47  		consulConfig := consul.DefaultConfig()
    48  		consulConfig.Address = address
    49  		consulConfig.HttpClient.Timeout = timeout
    50  
    51  		f.client, err = consul.NewClient(consulConfig)
    52  		if err != nil {
    53  			return false, fmt.Errorf("Failed to initialize consul client: %s", err)
    54  		}
    55  	}
    56  
    57  	// We'll try to detect consul by making a query to to the agent's self API.
    58  	// If we can't hit this URL consul is probably not running on this machine.
    59  	info, err := f.client.Agent().Self()
    60  	if err != nil {
    61  		// Clear any attributes set by a previous fingerprint.
    62  		f.clearConsulAttributes(node)
    63  
    64  		// Print a message indicating that the Consul Agent is not available
    65  		// anymore
    66  		if f.lastState == consulAvailable {
    67  			f.logger.Printf("[INFO] fingerprint.consul: consul agent is unavailable")
    68  		}
    69  		f.lastState = consulUnavailable
    70  		return false, nil
    71  	}
    72  
    73  	node.Attributes["consul.server"] = strconv.FormatBool(info["Config"]["Server"].(bool))
    74  	node.Attributes["consul.version"] = info["Config"]["Version"].(string)
    75  	node.Attributes["consul.revision"] = info["Config"]["Revision"].(string)
    76  	node.Attributes["unique.consul.name"] = info["Config"]["NodeName"].(string)
    77  	node.Attributes["consul.datacenter"] = info["Config"]["Datacenter"].(string)
    78  
    79  	node.Links["consul"] = fmt.Sprintf("%s.%s",
    80  		node.Attributes["consul.datacenter"],
    81  		node.Attributes["unique.consul.name"])
    82  
    83  	// If the Consul Agent was previously unavailable print a message to
    84  	// indicate the Agent is available now
    85  	if f.lastState == consulUnavailable {
    86  		f.logger.Printf("[INFO] fingerprint.consul: consul agent is available")
    87  	}
    88  	f.lastState = consulAvailable
    89  	return true, nil
    90  }
    91  
    92  // clearConsulAttributes removes consul attributes and links from the passed
    93  // Node.
    94  func (f *ConsulFingerprint) clearConsulAttributes(n *structs.Node) {
    95  	delete(n.Attributes, "consul.server")
    96  	delete(n.Attributes, "consul.version")
    97  	delete(n.Attributes, "consul.revision")
    98  	delete(n.Attributes, "unique.consul.name")
    99  	delete(n.Attributes, "consul.datacenter")
   100  	delete(n.Links, "consul")
   101  }
   102  
   103  func (f *ConsulFingerprint) Periodic() (bool, time.Duration) {
   104  	return true, 15 * time.Second
   105  }