Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client SDK changes for foundation based bare metal provisioning #352

87 changes: 79 additions & 8 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
const (
// libraryVersion = "v3"
defaultBaseURL = "https://%s/"
httpBaseURL = "http://%s/"
bhatipradeep marked this conversation as resolved.
Show resolved Hide resolved
// absolutePath = "api/nutanix/" + libraryVersion
// userAgent = "nutanix/" + libraryVersion
mediaType = "application/json"
Expand Down Expand Up @@ -52,14 +53,17 @@ type RequestCompletionCallback func(*http.Request, *http.Response, interface{})

// Credentials needed username and password
type Credentials struct {
URL string
Username string
Password string
Endpoint string
Port string
Insecure bool
SessionAuth bool
ProxyURL string
URL string
Username string
Password string
Endpoint string
Port string
Insecure bool
SessionAuth bool
ProxyURL string
FoundationEndpoint string
FoundationPort string
FoundationURL string
}

// AdditionalFilter specification for client side filters
Expand Down Expand Up @@ -132,6 +136,35 @@ func NewClient(credentials *Credentials, userAgent string, absolutePath string)
return c, nil
}

// NewBaseClient returns a basic http/https client based on isHttp flag
func NewBaseClient(credentials *Credentials, absolutePath string, isHttp bool) (*Client, error) {
if absolutePath == "" {
return nil, fmt.Errorf("absolutePath argument must be passed")
}

httpClient := http.DefaultClient

transCfg := &http.Transport{
// nolint:gas
TLSClientConfig: &tls.Config{InsecureSkipVerify: credentials.Insecure}, // ignore expired SSL certificates
}
httpClient.Transport = logging.NewTransport("Nutanix", transCfg)

urlExpr := defaultBaseURL
if isHttp {
urlExpr = httpBaseURL
}

baseURL, err := url.Parse(fmt.Sprintf(urlExpr, credentials.URL))
if err != nil {
return nil, err
}

c := &Client{credentials, httpClient, baseURL, "", nil, nil, absolutePath}

return c, nil
}

// NewRequest creates a request
func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) {
rel, errp := url.Parse(c.AbsolutePath + urlStr)
Expand Down Expand Up @@ -171,6 +204,37 @@ func (c *Client) NewRequest(ctx context.Context, method, urlStr string, body int
return req, nil
}

// NewRequest creates a request without authorisation headers
func (c *Client) NewUnAuthRequest(ctx context.Context, method, urlStr string, body interface{}) (*http.Request, error) {
rel, errp := url.Parse(c.AbsolutePath + urlStr)
if errp != nil {
return nil, errp
}

u := c.BaseURL.ResolveReference(rel)

buf := new(bytes.Buffer)

if body != nil {
err := json.NewEncoder(buf).Encode(body)

if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, u.String(), buf)

if err != nil {
return nil, err
}

req.Header.Add("Content-Type", mediaType)
req.Header.Add("Accept", mediaType)
req.Header.Add("User-Agent", c.UserAgent)

return req, nil
}

// NewUploadRequest Handles image uploads for image service
func (c *Client) NewUploadRequest(ctx context.Context, method, urlStr string, body []byte) (*http.Request, error) {
rel, errp := url.Parse(c.AbsolutePath + urlStr)
Expand Down Expand Up @@ -424,10 +488,17 @@ func CheckResponse(r *http.Response) error {
}
log.Print("[DEBUG] first nil check")

// foundation /image_nodes api error check
if errStruct, ok := res["error"]; ok {
return fmt.Errorf("error: %s", errStruct)
}

// karbon error check
if messageInfo, ok := res["message_info"]; ok {
return fmt.Errorf("error: %s", messageInfo)
}

//This check is also used for foundation /progress api errors
if message, ok := res["message"]; ok {
log.Print(message)
return fmt.Errorf("error: %s", message)
Expand Down
6 changes: 3 additions & 3 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ func setup() (*http.ServeMux, *Client, *httptest.Server) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)

client, _ := NewClient(&Credentials{"", "username", "password", "", "", true, false, ""}, testUserAgent, testAbsolutePath)
client, _ := NewClient(&Credentials{"", "username", "password", "", "", true, false, "", "", "", ""}, testUserAgent, testAbsolutePath)
client.BaseURL, _ = url.Parse(server.URL)

return mux, client, server
}

func TestNewClient(t *testing.T) {
c, err := NewClient(&Credentials{"foo.com", "username", "password", "", "", true, false, ""}, testUserAgent, testAbsolutePath)
c, err := NewClient(&Credentials{"foo.com", "username", "password", "", "", true, false, "", "", "", ""}, testUserAgent, testAbsolutePath)

if err != nil {
t.Errorf("Unexpected Error: %v", err)
Expand All @@ -49,7 +49,7 @@ func TestNewClient(t *testing.T) {
}

func TestNewRequest(t *testing.T) {
c, err := NewClient(&Credentials{"foo.com", "username", "password", "", "", true, false, ""}, testUserAgent, testAbsolutePath)
c, err := NewClient(&Credentials{"foo.com", "username", "password", "", "", true, false, "", "", "", ""}, testUserAgent, testAbsolutePath)

if err != nil {
t.Errorf("Unexpected Error: %v", err)
Expand Down
49 changes: 49 additions & 0 deletions client/foundation/foundation_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package foundation

import (
"github.com/terraform-providers/terraform-provider-nutanix/client"
)

const (
absolutePath = "foundation"
userAgent = "foundation"
)

//Foundation client with its services
type Client struct {

//base client
client *client.Client

//Service for Imaging Nodes and Cluster Creation
NodeImaging NodeImagingService

//Service for File Management in foundation VM
FileManagement FileManagementService
}

//This routine returns new Foundation API Client
func NewFoundationAPIClient(credentials client.Credentials) (*Client, error) {

//for foundation client, url should be foundation url
credentials.URL = credentials.FoundationURL
client, err := client.NewBaseClient(&credentials, absolutePath, true)

if err != nil {
return nil, err
}

//Fill user agent details
client.UserAgent = userAgent

foundationClient := &Client{
client: client,
NodeImaging: NodeImagingOperations{
client: client,
},
FileManagement: FileManagementOperations{
client: client,
},
}
return foundationClient, nil
}
41 changes: 41 additions & 0 deletions client/foundation/foundation_file_management_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package foundation

import (
"context"
"net/http"

"github.com/terraform-providers/terraform-provider-nutanix/client"
)

type FileManagementService interface {
ListNOSPackages() (*ListNOSPackagesResponse, error)
ListHypervisorISOs() (*ListHypervisorISOsResponse, error)
}

type FileManagementOperations struct {
client *client.Client
}

//Lists the available AOS packages in Foundation
func (fileManagementOperations FileManagementOperations) ListNOSPackages() (*ListNOSPackagesResponse, error) {
bhatipradeep marked this conversation as resolved.
Show resolved Hide resolved
ctx := context.TODO()
bhatipradeep marked this conversation as resolved.
Show resolved Hide resolved
path := "/enumerate_nos_packages"
req, err := fileManagementOperations.client.NewUnAuthRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}
listNOSPackagesResponse := new(ListNOSPackagesResponse)
return listNOSPackagesResponse, fileManagementOperations.client.Do(ctx, req, listNOSPackagesResponse)
}

//Lists the hypervisor ISOs available in Foundation
func (fileManagementOperations FileManagementOperations) ListHypervisorISOs() (*ListHypervisorISOsResponse, error) {
ctx := context.TODO()
path := "/enumerate_hypervisor_isos"
req, err := fileManagementOperations.client.NewUnAuthRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}
listHypervisorISOsResponse := new(ListHypervisorISOsResponse)
return listHypervisorISOsResponse, fileManagementOperations.client.Do(ctx, req, listHypervisorISOsResponse)
}
41 changes: 41 additions & 0 deletions client/foundation/foundation_node_imaging_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package foundation

import (
"context"
"net/http"

"github.com/terraform-providers/terraform-provider-nutanix/client"
)

type NodeImagingService interface {
ImageNodes(*ImageNodesInput) (*ImageNodesAPIResponse, error)
ImageNodesProgress(string) (*ImageNodesProgressResponse, error)
}

type NodeImagingOperations struct {
client *client.Client
}

func (nodeImagingOperations NodeImagingOperations) ImageNodes(imageNodeInput *ImageNodesInput) (*ImageNodesAPIResponse, error) {
ctx := context.TODO()
path := "/image_nodes"
req, err := nodeImagingOperations.client.NewUnAuthRequest(ctx, http.MethodPost, path, imageNodeInput)
if err != nil {
return nil, err
}

imageNodesAPIResponse := new(ImageNodesAPIResponse)
return imageNodesAPIResponse, nodeImagingOperations.client.Do(ctx, req, imageNodesAPIResponse)
}

//Gets progress of imaging session.
func (nodeImagingOperations NodeImagingOperations) ImageNodesProgress(session_id string) (*ImageNodesProgressResponse, error) {
ctx := context.TODO()
path := "/progress?session_id=" + session_id
req, err := nodeImagingOperations.client.NewUnAuthRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}
imageNodesProgressResponse := new(ImageNodesProgressResponse)
return imageNodesProgressResponse, nodeImagingOperations.client.Do(ctx, req, imageNodesProgressResponse)
}
Loading