github.com/bigcommerce/nomad@v0.9.3-bc/client/fingerprint/consul.go (about)

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