/
controller_client.go
169 lines (142 loc) · 4.24 KB
/
controller_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
// Copyright © 2018-2019 The OpenEBS Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/openebs/maya/pkg/util"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
// NewControllerClient create the new controller client
func NewControllerClient(address string) (*ControllerClient, error) {
address = strings.TrimPrefix(address, "tcp://")
if !strings.HasPrefix(address, "http") {
address = "http://" + address
}
if !strings.HasSuffix(address, "/v1") {
address += "/v1"
}
u, err := url.Parse(address)
if err != nil {
return nil, err
}
parts := strings.Split(u.Host, ":")
if len(parts) < 2 {
return nil, fmt.Errorf("Invalid address %s, must have a port in it", address)
}
return &ControllerClient{
Host: parts[0],
Address: address,
httpClient: &http.Client{Timeout: 2 * time.Second},
}, nil
}
// Post sends a POST request to the specified path and stores body in the value
// pointed to by resp.
func (c *ControllerClient) Post(path string, req, resp interface{}) error {
return c.Do("POST", path, req, resp)
}
// Do sends a request to the specified path and it stores JSON-decoded body
// from the response into the value pointed to by resp.
func (c *ControllerClient) Do(method, path string, req, resp interface{}) error {
b, err := json.Marshal(req)
if err != nil {
return err
}
bodyType := "application/json"
url := path
if !strings.HasPrefix(url, "http") {
url = c.Address + path
}
httpReq, err := http.NewRequest(method, url, bytes.NewBuffer(b))
if err != nil {
return err
}
httpReq.Header.Set("Content-Type", bodyType)
httpResp, err := http.DefaultClient.Do(httpReq)
if err != nil {
return err
}
defer httpResp.Body.Close()
if httpResp.StatusCode >= 300 {
content, _ := ioutil.ReadAll(httpResp.Body)
return fmt.Errorf("Bad response: %d %s: %s", httpResp.StatusCode, httpResp.Status, content)
}
if resp == nil {
return nil
}
return json.NewDecoder(httpResp.Body).Decode(resp)
}
// GetVolume returns Volumes from the specified path.
func GetVolume(path string) (*Volumes, error) {
var volume VolumeCollection
var c ControllerClient
err := c.Get(path+"/volumes", &volume)
if err != nil {
return nil, err
}
if len(volume.Data) == 0 {
return nil, errors.New("No volume found")
}
return &volume.Data[0], nil
}
// Get sends a request to the specified path and stores body in the value
// pointed to by obj.
func (c *ControllerClient) Get(path string, obj interface{}) error {
resp, err := http.Get(path)
if err != nil {
return err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
// ListReplicas to get the details of all the existing replicas
// which contains address and mode of those replicas (RW/R/W) as well as
// resource information.
func (c *ControllerClient) ListReplicas(path string) ([]Replica, error) {
var resp ReplicaCollection
err := c.Get(path+"/replicas", &resp)
return resp.Data, err
}
// GetVolumeStats is used to get the status of volume controller.It is used to
// get the response in json format and then the response is then decoded to the
// desired structure.
func (c *ControllerClient) GetVolumeStats(address string, api string, obj interface{}) (int, error) {
controller, err := NewControllerClient(address)
if err != nil {
return -1, err
}
url := controller.Address + api
resp, err := controller.httpClient.Get(url)
if resp != nil {
if resp.StatusCode == 500 {
return 500, util.ErrInternalServerError
} else if resp.StatusCode == 503 {
return 503, util.ErrServerUnavailable
}
} else {
return -1, util.ErrServerNotReachable
}
if err != nil {
return -1, err
}
defer resp.Body.Close()
rc := json.NewDecoder(resp.Body).Decode(obj)
return 0, rc
}