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  }