github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/fingerprint/vault.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	log "github.com/hashicorp/go-hclog"
    10  	"github.com/hashicorp/nomad/helper"
    11  	vapi "github.com/hashicorp/vault/api"
    12  )
    13  
    14  const (
    15  	vaultAvailable   = "available"
    16  	vaultUnavailable = "unavailable"
    17  )
    18  
    19  // VaultFingerprint is used to fingerprint for Vault
    20  type VaultFingerprint struct {
    21  	logger    log.Logger
    22  	client    *vapi.Client
    23  	lastState string
    24  }
    25  
    26  // NewVaultFingerprint is used to create a Vault fingerprint
    27  func NewVaultFingerprint(logger log.Logger) Fingerprint {
    28  	return &VaultFingerprint{logger: logger.Named("vault"), lastState: vaultUnavailable}
    29  }
    30  
    31  func (f *VaultFingerprint) Fingerprint(req *FingerprintRequest, resp *FingerprintResponse) error {
    32  	config := req.Config
    33  
    34  	if config.VaultConfig == nil || !config.VaultConfig.IsEnabled() {
    35  		return nil
    36  	}
    37  
    38  	// Only create the client once to avoid creating too many connections to
    39  	// Vault.
    40  	if f.client == nil {
    41  		vaultConfig, err := config.VaultConfig.ApiConfig()
    42  		if err != nil {
    43  			return fmt.Errorf("Failed to initialize the Vault client config: %v", err)
    44  		}
    45  
    46  		f.client, err = vapi.NewClient(vaultConfig)
    47  		if err != nil {
    48  			return fmt.Errorf("Failed to initialize Vault client: %s", err)
    49  		}
    50  	}
    51  
    52  	// Connect to vault and parse its information
    53  	status, err := f.client.Sys().SealStatus()
    54  	if err != nil {
    55  
    56  		// Print a message indicating that Vault is not available anymore
    57  		if f.lastState == vaultAvailable {
    58  			f.logger.Info("Vault is unavailable")
    59  		}
    60  		f.lastState = vaultUnavailable
    61  		return nil
    62  	}
    63  
    64  	resp.AddAttribute("vault.accessible", strconv.FormatBool(true))
    65  	// We strip the Vault prefix because < 0.6.2 the version looks like:
    66  	// status.Version = "Vault v0.6.1"
    67  	resp.AddAttribute("vault.version", strings.TrimPrefix(status.Version, "Vault "))
    68  	resp.AddAttribute("vault.cluster_id", status.ClusterID)
    69  	resp.AddAttribute("vault.cluster_name", status.ClusterName)
    70  
    71  	// If Vault was previously unavailable print a message to indicate the Agent
    72  	// is available now
    73  	if f.lastState == vaultUnavailable {
    74  		f.logger.Info("Vault is available")
    75  	}
    76  	f.lastState = vaultAvailable
    77  	resp.Detected = true
    78  	return nil
    79  }
    80  
    81  func (f *VaultFingerprint) Periodic() (bool, time.Duration) {
    82  	if f.lastState == vaultAvailable {
    83  		// Fingerprint infrequently once Vault is initially discovered with wide
    84  		// jitter to avoid thundering herds of fingerprints against central Vault
    85  		// servers.
    86  		return true, (30 * time.Second) + helper.RandomStagger(90*time.Second)
    87  	}
    88  	return true, 15 * time.Second
    89  }