From 386e9f2777c8936bd88a3cadf64e6b96f1cbdfac Mon Sep 17 00:00:00 2001 From: David Allen Date: Tue, 30 Jul 2024 14:03:34 -0600 Subject: [PATCH] Renamed smd package to client --- pkg/client/client.go | 87 ++++++++++++++++++++++++++++++++++++++ pkg/{smd => client}/smd.go | 75 ++++---------------------------- 2 files changed, 95 insertions(+), 67 deletions(-) create mode 100644 pkg/client/client.go rename pkg/{smd => client}/smd.go (50%) diff --git a/pkg/client/client.go b/pkg/client/client.go new file mode 100644 index 0000000..229471d --- /dev/null +++ b/pkg/client/client.go @@ -0,0 +1,87 @@ +package client + +import ( + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "net" + "net/http" + "os" + "time" + + "github.com/OpenCHAMI/magellan/internal/util" +) + +type Option func(*Client) + +// The 'Client' struct is a wrapper around the default http.Client +// that provides an extended API to work with functional options. +// It also provides functions that work with `collect` data. +type Client struct { + *http.Client +} + +// NewClient() creates a new client +func NewClient(opts ...Option) *Client { + client := &Client{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt(client) + } + return client +} + +func WithHttpClient(httpClient *http.Client) Option { + return func(c *Client) { + c.Client = httpClient + } +} + +func WithCertPool(certPool *x509.CertPool) Option { + if certPool == nil { + return func(c *Client) {} + } + return func(c *Client) { + c.Client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + InsecureSkipVerify: true, + }, + DisableKeepAlives: true, + Dial: (&net.Dialer{ + Timeout: 120 * time.Second, + KeepAlive: 120 * time.Second, + }).Dial, + TLSHandshakeTimeout: 120 * time.Second, + ResponseHeaderTimeout: 120 * time.Second, + } + } +} + +func WithSecureTLS(certPath string) Option { + cacert, err := os.ReadFile(certPath) + if err != nil { + return func(c *Client) {} + } + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(cacert) + return WithCertPool(certPool) +} + +// Post() is a simplified wrapper function that packages all of the +// that marshals a mapper into a JSON-formatted byte array, and then performs +// a request to the specified URL. +func (c *Client) Post(url string, data map[string]any, header util.HTTPHeader) (*http.Response, util.HTTPBody, error) { + // serialize data into byte array + body, err := json.Marshal(data) + if err != nil { + return nil, nil, fmt.Errorf("failed to marshal data for request: %v", err) + } + return util.MakeRequest(c.Client, url, http.MethodPost, body, header) +} + +func (c *Client) MakeRequest(url string, method string, body util.HTTPBody, header util.HTTPHeader) (*http.Response, util.HTTPBody, error) { + return util.MakeRequest(c.Client, url, method, body, header) +} diff --git a/pkg/smd/smd.go b/pkg/client/smd.go similarity index 50% rename from pkg/smd/smd.go rename to pkg/client/smd.go index 370841d..726c5f6 100644 --- a/pkg/smd/smd.go +++ b/pkg/client/smd.go @@ -1,16 +1,11 @@ -package smd +package client // See ref for API docs: // https://github.com/OpenCHAMI/hms-smd/blob/master/docs/examples.adoc // https://github.com/OpenCHAMI/hms-smd import ( - "crypto/tls" - "crypto/x509" "fmt" - "net" "net/http" - "os" - "time" "github.com/OpenCHAMI/magellan/internal/util" ) @@ -21,65 +16,11 @@ var ( Port = 27779 ) -type Option func(*Client) - -type Client struct { - *http.Client - CACertPool *x509.CertPool -} - -func NewClient(opts ...Option) *Client { - client := &Client{ - Client: http.DefaultClient, - } - for _, opt := range opts { - opt(client) - } - return client -} - -func WithHttpClient(httpClient *http.Client) Option { - return func(c *Client) { - c.Client = httpClient - } -} - -// This MakeRequest function is a wrapper around the util.MakeRequest function -// with a couple of niceties with using a smd.Client -func (c *Client) MakeRequest(url string, method string, body []byte, headers map[string]string) (*http.Response, []byte, error) { - return util.MakeRequest(c.Client, url, method, body, headers) -} - -func WithCertPool(certPool *x509.CertPool) Option { - return func(c *Client) { - c.Client.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: certPool, - InsecureSkipVerify: true, - }, - DisableKeepAlives: true, - Dial: (&net.Dialer{ - Timeout: 120 * time.Second, - KeepAlive: 120 * time.Second, - }).Dial, - TLSHandshakeTimeout: 120 * time.Second, - ResponseHeaderTimeout: 120 * time.Second, - } - } -} - -func WithSecureTLS(certPath string) Option { - cacert, _ := os.ReadFile(certPath) - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(cacert) - return WithCertPool(certPool) -} - -func (c *Client) GetRedfishEndpoints(headers map[string]string, opts ...Option) error { +func (c *Client) GetRedfishEndpoints(header util.HTTPHeader) error { url := makeEndpointUrl("/Inventory/RedfishEndpoints") - _, body, err := c.MakeRequest(url, "GET", nil, headers) + _, body, err := util.MakeRequest(c.Client, url, http.MethodGet, nil, header) if err != nil { - return fmt.Errorf("failed toget endpoint: %v", err) + return fmt.Errorf("failed to get endpoint: %v", err) } // fmt.Println(res) fmt.Println(string(body)) @@ -90,21 +31,21 @@ func (c *Client) GetComponentEndpoint(xname string) error { url := makeEndpointUrl("/Inventory/ComponentsEndpoints/" + xname) res, body, err := c.MakeRequest(url, "GET", nil, nil) if err != nil { - return fmt.Errorf("failed toget endpoint: %v", err) + return fmt.Errorf("failed to get endpoint: %v", err) } fmt.Println(res) fmt.Println(string(body)) return nil } -func (c *Client) AddRedfishEndpoint(data []byte, headers map[string]string) error { +func (c *Client) AddRedfishEndpoint(data map[string]any, headers util.HTTPHeader) error { if data == nil { - return fmt.Errorf("failed toadd redfish endpoint: no data found") + return fmt.Errorf("failed to add redfish endpoint: no data found") } // Add redfish endpoint via POST `/hsm/v2/Inventory/RedfishEndpoints` endpoint url := makeEndpointUrl("/Inventory/RedfishEndpoints") - res, body, err := c.MakeRequest(url, "POST", data, headers) + res, body, err := c.Post(url, data, headers) if res != nil { statusOk := res.StatusCode >= 200 && res.StatusCode < 300 if !statusOk {