1package diagnose
2
3import (
4	"context"
5	"fmt"
6	"strings"
7	"time"
8
9	"github.com/hashicorp/vault/sdk/physical"
10)
11
12const (
13	success   string = "success"
14	secretVal string = "diagnoseSecret"
15
16	LatencyWarning    string        = "Latency above 100 ms: "
17	DirAccessErr      string        = "Vault storage is directly connected to a Consul server."
18	DirAccessAdvice   string        = "We recommend connecting to a local agent."
19	AddrDNExistErr    string        = "Storage config address does not exist: 127.0.0.1:8500 will be used."
20	wrongRWValsPrefix string        = "Storage get and put gave wrong values: "
21	latencyThreshold  time.Duration = time.Millisecond * 100
22)
23
24func EndToEndLatencyCheckWrite(ctx context.Context, uuid string, b physical.Backend) (time.Duration, error) {
25	start := time.Now()
26	err := b.Put(context.Background(), &physical.Entry{Key: uuid, Value: []byte(secretVal)})
27	duration := time.Since(start)
28	if err != nil {
29		return time.Duration(0), err
30	}
31	if duration > latencyThreshold {
32		return duration, nil
33	}
34	return time.Duration(0), nil
35}
36
37func EndToEndLatencyCheckRead(ctx context.Context, uuid string, b physical.Backend) (time.Duration, error) {
38
39	start := time.Now()
40	val, err := b.Get(context.Background(), uuid)
41	duration := time.Since(start)
42	if err != nil {
43		return time.Duration(0), err
44	}
45	if val == nil {
46		return time.Duration(0), fmt.Errorf("No value found when reading generated data.")
47	}
48	if val.Key != uuid && string(val.Value) != secretVal {
49		return time.Duration(0), fmt.Errorf(wrongRWValsPrefix+"expecting %s as key and diagnose for value, but got %s, %s.", uuid, val.Key, val.Value)
50	}
51	if duration > latencyThreshold {
52		return duration, nil
53	}
54	return time.Duration(0), nil
55}
56func EndToEndLatencyCheckDelete(ctx context.Context, uuid string, b physical.Backend) (time.Duration, error) {
57
58	start := time.Now()
59	err := b.Delete(context.Background(), uuid)
60	duration := time.Since(start)
61	if err != nil {
62		return time.Duration(0), err
63	}
64	if duration > latencyThreshold {
65		return duration, nil
66	}
67	return time.Duration(0), nil
68}
69
70// ConsulDirectAccess verifies that consul is connecting to local agent,
71// versus directly to a remote server. We can only assume that the local address
72// is a server, not a client.
73func ConsulDirectAccess(config map[string]string) string {
74	configAddr, ok := config["address"]
75	if !ok {
76		return AddrDNExistErr
77	}
78	if !strings.Contains(configAddr, "localhost") && !strings.Contains(configAddr, "127.0.0.1") {
79		return DirAccessErr
80	}
81	return ""
82}
83