From 698589ddcc308089518ece8afb1ef195100856c7 Mon Sep 17 00:00:00 2001 From: Kienan Stewart Date: Sat, 24 Oct 2020 14:54:40 -0400 Subject: [PATCH] Add client to get cluster information and networks --- client.go | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ client_test.go | 44 +++++++++++++++++ go.mod | 3 ++ 3 files changed, 178 insertions(+) create mode 100644 client.go create mode 100644 client_test.go create mode 100644 go.mod diff --git a/client.go b/client.go new file mode 100644 index 0000000..ee65a51 --- /dev/null +++ b/client.go @@ -0,0 +1,131 @@ +package rapi + +import ( + "fmt" + "net/http" + "crypto/tls" + "encoding/json" + "io/ioutil" +) + +type RapiClient interface { + Do(request_type, path string) ([]byte, error) + GetClusterInformation() (map[string]interface{}, error) + GetNetworks() ([]map[string]interface{}, error) + GetNetworksBulk() ([]map[string]interface{}, error) + GetNetworkInfo(name string) (map[string]interface{}, error) +} + +type Client struct { + Username string + Password string + Host string + Port int + ApiVersion int +} + +func NewClient(username, password, host string, port, apiversion int) *Client { + return &Client{ + Username: username, + Password: password, + Host: host, + Port: port, + ApiVersion: apiversion, + } +} + +func (s *Client) GetClusterInformation() (map[string]interface{}, error) { + result, err := s.Do("GET", "info") + if err != nil { + return nil, err + } + data := make(map[string]interface{}) + err = json.Unmarshal(result, &data) + if err != nil { + return nil, err + } + return data, nil +} + +func (s *Client) GetNetworks() ([]map[string]interface{}, error) { + result, err := s.Do("GET", "networks") + if err != nil { + return nil, err + } + data := make([]map[string]interface{}, 0) + err = json.Unmarshal(result, &data) + if err != nil { + return nil, err + } + return data, nil +} + +func (s *Client) GetNetworksBulk() ([]map[string]interface{}, error) { + result, err := s.Do("GET", "networks?bulk=1") + if err != nil { + return nil, err + } + data := make([]map[string]interface{}, 0) + err = json.Unmarshal(result, &data) + if err != nil { + return nil, err + } + return data, nil +} + +func (s *Client) GetNetworkInformation(name string) (map[string]interface{}, error) { + result, err := s.Do("GET", "networks/" + name) + if err != nil { + return nil, err + } + data := make(map[string]interface{}) + err = json.Unmarshal(result, &data) + if err != nil { + return nil, err + } + return data, nil +} + +func (s *Client) Do(request_type, path string) ([]byte, error) { + req, err := s.GetRequest(request_type, path) + if err != nil { + return nil, err + } + result := make([]byte, 0) + result, err = s.DoRequest(req) + if err != nil { + return nil, err + } + return result, err +} + +func (s *Client) GetRequest(request_type, path string) (*http.Request, error) { + url := fmt.Sprintf("https://%s:%d/%d/%s", s.Host, s.Port, s.ApiVersion, path) + return http.NewRequest(request_type, url, nil) +} + +func (s *Client) GetHttpClient() (*http.Client) { + // Ganeti often has a self-signed certificate that is used for the RAPI + // @TODO This should be configural + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return &http.Client{Transport: tr} +} + +func (s *Client) DoRequest(req *http.Request) ([]byte, error) { + req.SetBasicAuth(s.Username, s.Password) + resp, err := s.GetHttpClient().Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if 200 != resp.StatusCode { + return nil, fmt.Errorf("%s", body) + } + return body, nil +} diff --git a/client_test.go b/client_test.go new file mode 100644 index 0000000..f82dc98 --- /dev/null +++ b/client_test.go @@ -0,0 +1,44 @@ +package rapi + +import ( + "testing" +) + +func TestClientInitialization(t *testing.T) { + NewClient("test", "test123", "ganeti.test", 5080, 2) +} + +func TestClusterInfo(t *testing.T) { + c := NewClient("test", "test123", "ganeti.test", 5080, 2) + _, err := c.GetClusterInformation() + if err != nil { + t.Errorf("Got error requesting cluster info %s", err) + } +} + +func TestGetNetworks(t *testing.T) { + c := NewClient("test", "test123", "ganeti.test", 5080, 2) + _, err := c.GetNetworks() + if err != nil { + t.Errorf("Got error requesting network list %s", err) + } +} + +func TestGetNetworksBulk(t *testing.T) { + c := NewClient("test", "test123", "ganeti.test", 5080, 2) + _, err := c.GetNetworksBulk() + if err != nil { + t.Errorf("Got error requesting network list %s", err) + } +} + +func TestGetNetworkInformation(t *testing.T) { + c := NewClient("test", "test123", "ganeti.test", 5080, 2) + n, err := c.GetNetworks() + if err != nil { + t.Errorf("Got error requesting network list %s", err) + } + if len(n) == 0 { + t.Errorf("No networks defined") + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0ee30b3 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module burntworld.ca/go-rapi-client + +go 1.15