forked from grafana-cold-storage/metrictank
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode.go
More file actions
160 lines (141 loc) · 3.61 KB
/
Copy pathnode.go
File metadata and controls
160 lines (141 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package cluster
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
"github.com/google/go-querystring/query"
"github.com/raintank/worldping-api/pkg/log"
)
//go:generate stringer -type=NodeState
type NodeState int
const (
NodeNotReady NodeState = iota
NodeReady
NodeUnreachable
)
var client = http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: time.Second * 5,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: time.Second,
},
Timeout: time.Second,
}
func NodeStateFromString(s string) NodeState {
switch s {
case "NodeNotReady":
return NodeNotReady
case "NodeReady":
return NodeReady
case "NodeUnreachable":
return NodeUnreachable
}
//default
return NodeNotReady
}
type Error struct {
code int
err error
}
func NewError(code int, err error) *Error {
return &Error{
code: code,
err: err,
}
}
// implement errors.Error interface
func (r *Error) Error() string {
return r.err.Error()
}
// implement response.Response
func (r *Error) Code() int {
return r.code
}
type Node struct {
Name string `json:"name"`
Version string `json:"version"`
Primary bool `json:"primary"`
PrimaryChange time.Time `json:"primaryChange"`
State NodeState `json:"state"`
Started time.Time `json:"started"`
StateChange time.Time `json:"stateChange"`
Partitions []int32 `json:"partitions"`
ApiPort int `json:"apiPort"`
ApiScheme string `json:"apiScheme"`
Updated time.Time `json:"updated"`
RemoteAddr string `json:"remoteAddr"`
local bool
}
func (n Node) RemoteURL() string {
return fmt.Sprintf("%s://%s:%d", n.ApiScheme, n.RemoteAddr, n.ApiPort)
}
func (n Node) IsReady() bool {
return n.State == NodeReady
}
func (n Node) IsLocal() bool {
return n.local
}
func (n Node) Get(path string, query interface{}) ([]byte, error) {
if query != nil {
qstr, err := toQueryString(query)
if err != nil {
return nil, NewError(http.StatusInternalServerError, err)
}
path = path + "?" + qstr
}
addr := n.RemoteURL() + path
req, err := http.NewRequest("GET", addr, nil)
if err != nil {
return nil, NewError(http.StatusInternalServerError, err)
}
rsp, err := client.Do(req)
if err != nil {
log.Error(3, "CLU Node: %s unreachable. %s", n.Name, err.Error())
return nil, NewError(http.StatusServiceUnavailable, fmt.Errorf("cluster node unavailable"))
}
return handleResp(rsp)
}
func (n Node) Post(path string, body interface{}) ([]byte, error) {
b, err := json.Marshal(body)
if err != nil {
return nil, NewError(http.StatusInternalServerError, err)
}
var reader *bytes.Reader
reader = bytes.NewReader(b)
addr := n.RemoteURL() + path
req, err := http.NewRequest("POST", addr, reader)
if err != nil {
return nil, NewError(http.StatusInternalServerError, err)
}
req.Header.Add("Content-Type", "application/json")
rsp, err := client.Do(req)
if err != nil {
log.Error(3, "CLU Node: %s unreachable. %s", n.Name, err.Error())
return nil, NewError(http.StatusServiceUnavailable, fmt.Errorf("cluster node unavailable"))
}
return handleResp(rsp)
}
func handleResp(rsp *http.Response) ([]byte, error) {
defer rsp.Body.Close()
if rsp.StatusCode != 200 {
return nil, NewError(rsp.StatusCode, fmt.Errorf(rsp.Status))
}
return ioutil.ReadAll(rsp.Body)
}
// Convert an interface{} to a urlencoded querystring
func toQueryString(q interface{}) (string, error) {
v, err := query.Values(q)
if err != nil {
return "", err
}
return v.Encode(), nil
}