Commit a94c83b7 authored by Alex Dadgar's avatar Alex Dadgar Committed by GitHub
Browse files

Merge pull request #1675 from hashicorp/f-vault-fingerprint

Fingerprint Vault
parents 4277583e f9391f04
Showing with 132 additions and 13 deletions
+132 -13
......@@ -24,7 +24,7 @@ type ConsulFingerprint struct {
lastState string
}
// NewConsulFingerprint is used to create an OS fingerprint
// NewConsulFingerprint is used to create a Consul fingerprint
func NewConsulFingerprint(logger *log.Logger) Fingerprint {
return &ConsulFingerprint{logger: logger, lastState: consulUnavailable}
}
......
......@@ -4,7 +4,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/hashicorp/nomad/client/config"
......@@ -12,11 +12,6 @@ import (
)
func TestConsulFingerprint(t *testing.T) {
addr := os.Getenv("CONSUL_HTTP_ADDR")
if addr == "" {
t.Skipf("No consul process running, skipping test")
}
fp := NewConsulFingerprint(testLogger())
node := &structs.Node{
Attributes: make(map[string]string),
......@@ -29,6 +24,7 @@ func TestConsulFingerprint(t *testing.T) {
defer ts.Close()
config := config.DefaultConfig()
config.ConsulConfig.Addr = strings.TrimPrefix(ts.URL, "http://")
ok, err := fp.Fingerprint(config, node)
if err != nil {
......
......@@ -17,6 +17,7 @@ const (
func init() {
builtinFingerprintMap["arch"] = NewArchFingerprint
builtinFingerprintMap["consul"] = NewConsulFingerprint
builtinFingerprintMap["cpu"] = NewCPUFingerprint
builtinFingerprintMap["env_aws"] = NewEnvAWSFingerprint
builtinFingerprintMap["env_gce"] = NewEnvGCEFingerprint
......@@ -25,6 +26,7 @@ func init() {
builtinFingerprintMap["network"] = NewNetworkFingerprint
builtinFingerprintMap["nomad"] = NewNomadFingerprint
builtinFingerprintMap["storage"] = NewStorageFingerprint
builtinFingerprintMap["vault"] = NewVaultFingerprint
// Initialize the list of available fingerprinters per platform. Each
// platform defines its own list of available fingerprinters.
......
package fingerprint
import (
"fmt"
"log"
"strconv"
"strings"
"time"
client "github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/nomad/structs"
vapi "github.com/hashicorp/vault/api"
)
const (
vaultAvailable = "available"
vaultUnavailable = "unavailable"
)
// ConsulFingerprint is used to fingerprint the architecture
type VaultFingerprint struct {
logger *log.Logger
client *vapi.Client
lastState string
}
// NewVaultFingerprint is used to create a Vault fingerprint
func NewVaultFingerprint(logger *log.Logger) Fingerprint {
return &VaultFingerprint{logger: logger, lastState: vaultUnavailable}
}
func (f *VaultFingerprint) Fingerprint(config *client.Config, node *structs.Node) (bool, error) {
if config.VaultConfig == nil || !config.VaultConfig.Enabled {
return false, nil
}
// Only create the client once to avoid creating too many connections to
// Vault.
if f.client == nil {
vaultConfig, err := config.VaultConfig.ApiConfig()
if err != nil {
return false, fmt.Errorf("Failed to initialize the Vault client config: %v", err)
}
f.client, err = vapi.NewClient(vaultConfig)
if err != nil {
return false, fmt.Errorf("Failed to initialize Vault client: %s", err)
}
}
// Connect to vault and parse its information
status, err := f.client.Sys().SealStatus()
if err != nil {
// Clear any attributes set by a previous fingerprint.
f.clearVaultAttributes(node)
// Print a message indicating that Vault is not available anymore
if f.lastState == vaultAvailable {
f.logger.Printf("[INFO] fingerprint.consul: Vault is unavailable")
}
f.lastState = vaultUnavailable
return false, nil
}
node.Attributes["vault.accessible"] = strconv.FormatBool(true)
// We strip the Vault prefix becasue < 0.6.2 the version looks like:
// status.Version = "Vault v0.6.1"
node.Attributes["vault.version"] = strings.TrimPrefix(status.Version, "Vault ")
node.Attributes["vault.cluster_id"] = status.ClusterID
node.Attributes["vault.cluster_name"] = status.ClusterName
// If Vault was previously unavailable print a message to indicate the Agent
// is available now
if f.lastState == vaultUnavailable {
f.logger.Printf("[INFO] fingerprint.vault: Vault is available")
}
f.lastState = vaultAvailable
return true, nil
}
func (f *VaultFingerprint) clearVaultAttributes(n *structs.Node) {
delete(n.Attributes, "vault.accessible")
delete(n.Attributes, "vault.version")
delete(n.Attributes, "vault.cluster_id")
delete(n.Attributes, "vault.cluster_name")
}
func (f *VaultFingerprint) Periodic() (bool, time.Duration) {
return true, 15 * time.Second
}
package fingerprint
import (
"testing"
"github.com/hashicorp/nomad/client/config"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/testutil"
)
func TestVaultFingerprint(t *testing.T) {
tv := testutil.NewTestVault(t).Start()
defer tv.Stop()
fp := NewVaultFingerprint(testLogger())
node := &structs.Node{
Attributes: make(map[string]string),
}
config := config.DefaultConfig()
config.VaultConfig = tv.Config
ok, err := fp.Fingerprint(config, node)
if err != nil {
t.Fatalf("Failed to fingerprint: %s", err)
}
if !ok {
t.Fatalf("Failed to apply node attributes")
}
assertNodeAttributeContains(t, node, "vault.accessible")
assertNodeAttributeContains(t, node, "vault.version")
assertNodeAttributeContains(t, node, "vault.cluster_id")
assertNodeAttributeContains(t, node, "vault.cluster_name")
}
......@@ -149,10 +149,6 @@ func NewVaultClient(config *config.VaultConfig, logger *log.Logger, tokenDeriver
return nil, nil
}
if config.TaskTokenTTL == "" {
return nil, fmt.Errorf("task_token_ttl not set")
}
if logger == nil {
return nil, fmt.Errorf("nil logger")
}
......@@ -240,8 +236,8 @@ OUTER:
case <-retryTimer.C:
// Ensure the API is reachable
if _, err := c.client.Sys().InitStatus(); err != nil {
c.logger.Printf("[WARN] client.vault: failed to contact Vault API. Retrying in %v",
c.config.ConnectionRetryIntv)
c.logger.Printf("[WARN] client.vault: failed to contact Vault API. Retrying in %v: %v",
c.config.ConnectionRetryIntv, err)
retryTimer.Reset(c.config.ConnectionRetryIntv)
continue OUTER
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment