Add Makefile
[vaultmon/.git] / vault.go
1 package main
2
3 import (
4         "encoding/json"
5         "fmt"
6         "io/ioutil"
7         "net/http"
8
9         log "github.com/sirupsen/logrus"
10 )
11
12 const (
13         HealthEndpointURL = "/v1/sys/health"
14         LeaderEndpointURL = "/v1/sys/leader"
15
16         // Vault Health Status https://www.vaultproject.io/api/system/health.html
17         VaultActive   = http.StatusOK
18         VaultStandby  = http.StatusTooManyRequests
19         VaultRecovery = 472
20         VaultNotReady = http.StatusNotImplemented
21         VaultSealed   = http.StatusServiceUnavailable
22 )
23
24 type Vault struct {
25         URL              string
26         ConnectionStatus string
27         ClusterStatus    string
28 }
29
30 type VaultSealedResult struct {
31         Sealed bool `json:"sealed"`
32 }
33
34 func (v *Vault) CheckHealth() (bool, error) {
35         healthURL := v.URL + HealthEndpointURL
36         cnx := NewConnection(healthURL)
37         log.Debugf("Vault Connection on %s", healthURL)
38         resp, err := cnx.Head()
39         if err != nil {
40                 return false, err
41         }
42         defer resp.Body.Close()
43
44         log.Debugf("Vault CheckHealth response: %s", resp.Status)
45
46         return isHealthy(resp.StatusCode), nil
47 }
48
49 func (v *Vault) CheckCluster() (bool, error) {
50         vaultFilter := make(map[string]string)
51         vaultFilter["Name"] = "tag:Cluster"
52         vaultFilter["Value"] = "theknowledge"
53
54         provider := newEC2Provider()
55         vaultNodeIps, err := provider.GetInstancesPrivateIps(vaultFilter)
56         if err != nil {
57                 return false, err
58         }
59
60         for _, nodeIp := range vaultNodeIps {
61                 healthURL := "https://" + nodeIp + ":8200" + HealthEndpointURL
62                 if sealed, err := isSealed(healthURL); sealed {
63                         return false, err
64                 }
65         }
66
67         return true, nil
68 }
69
70 func isHealthy(statusCode int) bool {
71         return statusCode == VaultActive || statusCode == VaultStandby
72 }
73
74 func isSealed(healthURL string) (bool, error) {
75         cnx := NewConnection(healthURL)
76         log.Debugf("Vault isSealed node connection on %s", healthURL)
77         resp, err := cnx.Get()
78         if err != nil {
79                 return false, err
80         }
81         defer resp.Body.Close()
82
83         log.Debugf("Vault isSealed connection response: %s", resp.Status)
84         if resp.StatusCode == VaultSealed {
85                 return true, nil
86         }
87
88         buf, err := ioutil.ReadAll(resp.Body)
89         if err != nil {
90                 return false, err
91         }
92
93         var result VaultSealedResult
94
95         err = json.Unmarshal(buf, &result)
96         if err != nil {
97                 return false, err
98         }
99
100         log.Debugf("Vault isSealed JSON result: %+v", result)
101
102         return result.Sealed, nil
103 }
104
105 func (v *Vault) Test() (bool, string) {
106         // test health
107         result, err := v.CheckHealth()
108         if err != nil {
109                 log.Errorf("Vault CheckHealth error: %s", err)
110                 v.ConnectionStatus = "KO"
111         }
112
113         if result == false {
114                 v.ConnectionStatus = "KO"
115         } else {
116                 v.ConnectionStatus = "OK"
117         }
118         log.Debugf("Vault CheckHealth result: %t", result)
119
120         // test cluster
121         result, err = v.CheckCluster()
122         if err != nil {
123                 log.Errorf("Vault CheckCluster error: %s", err)
124                 v.ClusterStatus = "KO"
125         }
126
127         if result == false {
128                 v.ClusterStatus = "KO"
129         } else {
130                 v.ClusterStatus = "OK"
131         }
132         log.Debugf("Vault CheckCluster result: %t", result)
133
134         return result, fmt.Sprintf("> %s `%s` status *%s*. Cluster status *%s*.", v.Name(), v.URL, v.ConnectionStatus, v.ClusterStatus)
135 }
136
137 func (v *Vault) Name() string {
138         return "Vault"
139 }
140
141 func NewVault(url string) CheckProvider {
142         return &Vault{URL: url}
143 }