forked from spaceapegames/go-wavefront
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
171 lines (144 loc) · 4.44 KB
/
client.go
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
161
162
163
164
165
166
167
168
169
170
171
// Package wavefront provides a library for interacting with the Wavefront API,
// along with a writer for sending metrics to a Wavefront proxy.
package wavefront
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
// Wavefronter is an interface that a Wavefront client must satisfy
// (generally this is abstracted for easier testing)
type Wavefronter interface {
NewRequest(method, path string, params *map[string]string, body []byte) (*http.Request, error)
Do(req *http.Request) (io.ReadCloser, error)
}
// Config is used to hold configuration used when constructing a Client
type Config struct {
// Address is the address of the Wavefront API, of the form example.wavefront.com
Address string
// Token is an authentication token that will be passed with all requests
Token string
// Timeout exposes the http client timeout
// https://golang.org/src/net/http/client.go
Timeout time.Duration
// SET HTTP Proxy configuration
HttpProxy string
// SkipTLSVerify disables SSL certificate checking and should be used for
// testing only
SkipTLSVerify bool
}
// Client is used to generate API requests against the Wavefront API.
type Client struct {
// Config is a Config object that will be used to construct requests
Config *Config
// BaseURL is the full URL of the Wavefront API, of the form
// https://example.wavefront.com/api/v2
BaseURL *url.URL
// httpClient is the client that will be used to make requests against the API.
httpClient *http.Client
// debug, if set, will cause all requests to be dumped to the screen before sending.
debug bool
}
// NewClient returns a new Wavefront client according to the given Config
func NewClient(config *Config) (*Client, error) {
baseURL, err := url.Parse("https://" + config.Address + "/api/v2/")
if err != nil {
return nil, err
}
// Added timeout to http client
// Timeout of zero means no timeout
h := &http.Client{
Timeout: config.Timeout,
Transport: &http.Transport{
TLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{},
},
}
// need to disable http/2 as it doesn't play nicely with nginx
// to do so we set TLSNextProto to an empty, non-nil map
c := &Client{
Config: config,
BaseURL: baseURL,
httpClient: h,
debug: false,
}
// ENABLE HTTP Proxy
if config.HttpProxy != "" {
proxyUrl, _ := url.Parse(config.HttpProxy)
c.httpClient.Transport = &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
}
}
//For testing ONLY
if config.SkipTLSVerify == true {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
c.httpClient.Transport = tr
}
return c, nil
}
// NewRequest creates a request object to query the Wavefront API.
// Path is a relative URI that should be specified with no trailing slash,
// it will be resolved against the BaseURL of the client.
// Params should be passed as a map[string]string, these will be converted
// to query parameters.
func (c Client) NewRequest(method, path string, params *map[string]string, body []byte) (*http.Request, error) {
rel, err := url.Parse(path)
if err != nil {
return nil, err
}
url := c.BaseURL.ResolveReference(rel)
if params != nil {
q := url.Query()
for k, v := range *params {
q.Set(k, v)
}
url.RawQuery = q.Encode()
}
req, err := http.NewRequest(method, url.String(), nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.Config.Token))
req.Header.Add("Accept", "application/json")
if body != nil {
req.Header.Add("Content-Type", "application/json")
req.Body = ioutil.NopCloser(bytes.NewReader(body))
}
return req, nil
}
// Do executes a request against the Wavefront API.
// The response body is returned if the request is successful, and should
// be closed by the requester.
func (c Client) Do(req *http.Request) (io.ReadCloser, error) {
if c.debug == true {
d, err := httputil.DumpRequestOut(req, true)
if err != nil {
return nil, err
}
fmt.Printf("%s\n", d)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("server returned %s\n", resp.Status)
}
return nil, fmt.Errorf("server returned %s\n%s\n", resp.Status, string(body))
}
return resp.Body, nil
}
// Debug enables dumping http request objects to stdout
func (c *Client) Debug(enable bool) {
c.debug = enable
}