github.com/yasker/longhorn-engine@v0.0.0-20160621014712-6ed6cfca0729/controller/client/controller_client.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "strings" 11 12 "github.com/Sirupsen/logrus" 13 "github.com/rancher/longhorn/controller/rest" 14 ) 15 16 type ControllerClient struct { 17 controller string 18 } 19 20 func NewControllerClient(controller string) *ControllerClient { 21 if !strings.HasSuffix(controller, "/v1") { 22 controller += "/v1" 23 } 24 return &ControllerClient{ 25 controller: controller, 26 } 27 } 28 29 func (c *ControllerClient) Start(replicas ...string) error { 30 volume, err := c.GetVolume() 31 if err != nil { 32 return err 33 } 34 35 return c.post(volume.Actions["start"], rest.StartInput{ 36 Replicas: replicas, 37 }, nil) 38 } 39 40 func (c *ControllerClient) RevertVolume(name string) (*rest.Volume, error) { 41 volume, err := c.GetVolume() 42 if err != nil { 43 return nil, err 44 } 45 46 input := &rest.RevertInput{ 47 Name: name, 48 } 49 50 output := &rest.Volume{} 51 52 err = c.post(volume.Actions["revert"], input, output) 53 if err != nil { 54 return nil, err 55 } 56 57 return output, err 58 } 59 60 func (c *ControllerClient) Snapshot(name string) (string, error) { 61 volume, err := c.GetVolume() 62 if err != nil { 63 return "", err 64 } 65 66 input := &rest.SnapshotInput{ 67 Name: name, 68 } 69 output := &rest.SnapshotOutput{} 70 err = c.post(volume.Actions["snapshot"], input, output) 71 if err != nil { 72 return "", err 73 } 74 75 return output.Id, err 76 } 77 78 func (c *ControllerClient) RevertSnapshot(snapshot string) error { 79 volume, err := c.GetVolume() 80 if err != nil { 81 return err 82 } 83 84 return c.post(volume.Actions["revert"], rest.RevertInput{ 85 Name: snapshot, 86 }, nil) 87 } 88 89 func (c *ControllerClient) ListJournal(limit int) error { 90 err := c.post("/journal", &rest.JournalInput{Limit: limit}, nil) 91 return err 92 } 93 94 func (c *ControllerClient) ListReplicas() ([]rest.Replica, error) { 95 var resp rest.ReplicaCollection 96 err := c.get("/replicas", &resp) 97 return resp.Data, err 98 } 99 100 func (c *ControllerClient) CreateReplica(address string) (*rest.Replica, error) { 101 var resp rest.Replica 102 err := c.post("/replicas", &rest.Replica{ 103 Address: address, 104 }, &resp) 105 return &resp, err 106 } 107 108 func (c *ControllerClient) DeleteReplica(address string) (*rest.Replica, error) { 109 reps, err := c.ListReplicas() 110 if err != nil { 111 return nil, err 112 } 113 114 for _, rep := range reps { 115 if rep.Address == address { 116 httpReq, err := http.NewRequest("DELETE", rep.Links["self"], nil) 117 if err != nil { 118 return nil, err 119 } 120 httpResp, err := http.DefaultClient.Do(httpReq) 121 if err != nil { 122 return nil, err 123 } 124 if httpResp.StatusCode >= 300 { 125 content, _ := ioutil.ReadAll(httpResp.Body) 126 return nil, fmt.Errorf("Bad response: %d %s: %s", httpResp.StatusCode, httpResp.Status, content) 127 } 128 return &rep, nil 129 } 130 } 131 132 return nil, nil 133 } 134 135 func (c *ControllerClient) UpdateReplica(replica rest.Replica) (rest.Replica, error) { 136 var resp rest.Replica 137 err := c.put(replica.Links["self"], &replica, &resp) 138 return resp, err 139 } 140 141 func (c *ControllerClient) GetVolume() (*rest.Volume, error) { 142 var volumes rest.VolumeCollection 143 144 err := c.get("/volumes", &volumes) 145 if err != nil { 146 return nil, err 147 } 148 149 if len(volumes.Data) == 0 { 150 return nil, errors.New("No volume found") 151 } 152 153 return &volumes.Data[0], nil 154 } 155 156 func (c *ControllerClient) post(path string, req, resp interface{}) error { 157 return c.do("POST", path, req, resp) 158 } 159 160 func (c *ControllerClient) put(path string, req, resp interface{}) error { 161 return c.do("PUT", path, req, resp) 162 } 163 164 func (c *ControllerClient) do(method, path string, req, resp interface{}) error { 165 b, err := json.Marshal(req) 166 if err != nil { 167 return err 168 } 169 170 bodyType := "application/json" 171 url := path 172 if !strings.HasPrefix(url, "http") { 173 url = c.controller + path 174 } 175 176 logrus.Debugf("%s %s", method, url) 177 httpReq, err := http.NewRequest(method, url, bytes.NewBuffer(b)) 178 if err != nil { 179 return err 180 } 181 httpReq.Header.Set("Content-Type", bodyType) 182 183 httpResp, err := http.DefaultClient.Do(httpReq) 184 if err != nil { 185 return err 186 } 187 defer httpResp.Body.Close() 188 189 if httpResp.StatusCode >= 300 { 190 content, _ := ioutil.ReadAll(httpResp.Body) 191 return fmt.Errorf("Bad response: %d %s: %s", httpResp.StatusCode, httpResp.Status, content) 192 } 193 194 if resp == nil { 195 return nil 196 } 197 198 return json.NewDecoder(httpResp.Body).Decode(resp) 199 } 200 201 func (c *ControllerClient) get(path string, obj interface{}) error { 202 resp, err := http.Get(c.controller + path) 203 if err != nil { 204 return err 205 } 206 defer resp.Body.Close() 207 208 return json.NewDecoder(resp.Body).Decode(obj) 209 }