diff --git a/CHANGELOG.md b/CHANGELOG.md index 283c8895..c14f5684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Added support for v4 client creation. + ### Added - Added support for getting information about an AZ given a uuid. diff --git a/go.mod b/go.mod index f00b8630..c7bc0340 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,11 @@ require ( github.com/google/uuid v1.3.0 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/keploy/go-sdk v0.7.2 + github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4 v4.0.2-alpha.2 + github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4 v4.0.1-alpha.1 + github.com/nutanix/ntnx-api-golang-clients/prism-go-client/v4 v4.0.2-alpha.1 + github.com/nutanix/ntnx-api-golang-clients/storage-go-client/v4 v4.0.2-alpha.3 + github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4 v4.0.2-alpha.1 github.com/onsi/ginkgo/v2 v2.7.0 github.com/onsi/gomega v1.26.0 github.com/stretchr/testify v1.8.1 @@ -46,6 +51,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -63,6 +69,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect github.com/tidwall/gjson v1.14.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect diff --git a/go.sum b/go.sum index 700a5bf8..3e41a0a9 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,13 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -163,6 +168,16 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4 v4.0.2-alpha.2 h1:GwunZWdO6J0X1xbTy220AIXMap6I9L5JedOzFussS/o= +github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4 v4.0.2-alpha.2/go.mod h1:sd4Fnk6MVfEDVY+8WyRoQTmLhi2SgZ3riySWErVHf8E= +github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4 v4.0.1-alpha.1 h1:i9apB9rDAF/u4GXvCG2ZhpWOtlKm0TtJMyBFRwVpiac= +github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4 v4.0.1-alpha.1/go.mod h1:+eZgV1+xL/r84qmuFSVt5R8OFRO70rEz92jOnVgJNco= +github.com/nutanix/ntnx-api-golang-clients/prism-go-client/v4 v4.0.2-alpha.1 h1:bQ5e0f0qM88HDaoR9nlff7C39254jSAaAtEQ7wkdzVs= +github.com/nutanix/ntnx-api-golang-clients/prism-go-client/v4 v4.0.2-alpha.1/go.mod h1:Yhk+xD4mN90OKEHnk5ARf97CX5p4+MEC/B/YIVoZeZ0= +github.com/nutanix/ntnx-api-golang-clients/storage-go-client/v4 v4.0.2-alpha.3 h1:K3I9YtqKcKKxSL4+tcxnFeLOoaptiVlpsOJ9Xzq3shM= +github.com/nutanix/ntnx-api-golang-clients/storage-go-client/v4 v4.0.2-alpha.3/go.mod h1:kz3gO87xtWnPOCP2kN7yw5LvCDVRnvg8BOWL7CarqXA= +github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4 v4.0.2-alpha.1 h1:ISAnkmh9xZkRaaCX+kWGxQjQl/8qRNY7qnH5vfzphCw= +github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4 v4.0.2-alpha.1/go.mod h1:CaWm4GFpAjQQDc6YXl/dUDrHpuW54h8j6Cj7EslE4Qk= github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= @@ -185,11 +200,14 @@ github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -301,6 +319,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/v4/v4.go b/v4/v4.go new file mode 100644 index 00000000..21b93b4d --- /dev/null +++ b/v4/v4.go @@ -0,0 +1,169 @@ +package v4 + +import ( + "encoding/base64" + "fmt" + "net/url" + "strconv" + + prismgoclient "github.com/nutanix-cloud-native/prism-go-client" + clusterApi "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/api" + clusterClient "github.com/nutanix/ntnx-api-golang-clients/clustermgmt-go-client/v4/client" + networkingApi "github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4/api" + networkingClient "github.com/nutanix/ntnx-api-golang-clients/networking-go-client/v4/client" + prismApi "github.com/nutanix/ntnx-api-golang-clients/prism-go-client/v4/api" + prismClient "github.com/nutanix/ntnx-api-golang-clients/prism-go-client/v4/client" + storageApi "github.com/nutanix/ntnx-api-golang-clients/storage-go-client/v4/api" + storageClient "github.com/nutanix/ntnx-api-golang-clients/storage-go-client/v4/client" + vmApi "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/api" + vmClient "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/client" +) + +const ( + defaultEndpointPort = "9440" + authorizationHeader = "Authorization" +) + +// Client manages the V4 API +type Client struct { + VmApiInstance *vmApi.VmApi + ImagesApiInstance *vmApi.ImagesApi + SubnetApiInstance *networkingApi.SubnetApi + SubnetReserveUnreserveIPAPIInstance *networkingApi.SubnetReserveUnreserveIpApi + ClusterApiInstance *clusterApi.ClusterApi + TasksApiInstance *prismApi.TaskApi + StorageContainerAPI *storageApi.StorageContainerApi +} + +type endpointInfo struct { + host string + port int +} + +// NewV4Client return a internal to operate V4 resources +func NewV4Client(credentials prismgoclient.Credentials) (*Client, error) { + if credentials.Username == "" || credentials.Password == "" || credentials.Endpoint == "" { + return nil, fmt.Errorf("username, password and endpoint are required") + } + + v4Client := &Client{} + + if err := initVmApiInstance(v4Client, credentials); err != nil { + return nil, fmt.Errorf("failed to create VM API instance: %v", err) + } + + if err := initSubnetApiInstance(v4Client, credentials); err != nil { + return nil, fmt.Errorf("failed to create Subnet API instance: %v", err) + } + + if err := initClusterApiInstance(v4Client, credentials); err != nil { + return nil, fmt.Errorf("failed to create Cluster API instance: %v", err) + } + + if err := initTasksApiInstance(v4Client, credentials); err != nil { + return nil, fmt.Errorf("failed to create Tasks API instance: %v", err) + } + + if err := initStorageApiInstance(v4Client, credentials); err != nil { + return nil, fmt.Errorf("failed to create Storage API instance: %v", err) + } + + return v4Client, nil +} + +func initVmApiInstance(v4Client *Client, credentials prismgoclient.Credentials) error { + ep, err := getEndpointInfo(credentials) + if err != nil { + return err + } + apiClientInstance := vmClient.NewApiClient() + apiClientInstance.VerifySSL = !credentials.Insecure + apiClientInstance.Host = ep.host + apiClientInstance.Port = ep.port + apiClientInstance.AddDefaultHeader( + authorizationHeader, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Username, credentials.Password))))) + v4Client.VmApiInstance = vmApi.NewVmApi(apiClientInstance) + v4Client.ImagesApiInstance = vmApi.NewImagesApi(apiClientInstance) + return nil +} + +func initClusterApiInstance(v4Client *Client, credentials prismgoclient.Credentials) error { + ep, err := getEndpointInfo(credentials) + if err != nil { + return err + } + apiClientInstance := clusterClient.NewApiClient() + apiClientInstance.VerifySSL = !credentials.Insecure + apiClientInstance.Host = ep.host + apiClientInstance.Port = ep.port + apiClientInstance.AddDefaultHeader( + authorizationHeader, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Username, credentials.Password))))) + v4Client.ClusterApiInstance = clusterApi.NewClusterApi(apiClientInstance) + return nil +} + +func initTasksApiInstance(v4Client *Client, credentials prismgoclient.Credentials) error { + ep, err := getEndpointInfo(credentials) + if err != nil { + return err + } + apiClientInstance := prismClient.NewApiClient() + apiClientInstance.VerifySSL = !credentials.Insecure + apiClientInstance.Host = ep.host + apiClientInstance.Port = ep.port + apiClientInstance.AddDefaultHeader( + authorizationHeader, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Username, credentials.Password))))) + v4Client.TasksApiInstance = prismApi.NewTaskApi(apiClientInstance) + return nil +} + +func initSubnetApiInstance(v4Client *Client, credentials prismgoclient.Credentials) error { + ep, err := getEndpointInfo(credentials) + if err != nil { + return err + } + apiClientInstance := networkingClient.NewApiClient() + apiClientInstance.SetVerifySSL(!credentials.Insecure) + apiClientInstance.Host = ep.host + apiClientInstance.Port = ep.port + apiClientInstance.AddDefaultHeader( + authorizationHeader, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Username, credentials.Password))))) + v4Client.SubnetApiInstance = networkingApi.NewSubnetApi(apiClientInstance) + v4Client.SubnetReserveUnreserveIPAPIInstance = networkingApi.NewSubnetReserveUnreserveIpApi(apiClientInstance) + return nil +} + +func initStorageApiInstance(v4Client *Client, credentials prismgoclient.Credentials) error { + ep, err := getEndpointInfo(credentials) + if err != nil { + return err + } + apiClientInstance := storageClient.NewApiClient() + apiClientInstance.SetVerifySSL(!credentials.Insecure) + apiClientInstance.Host = ep.host + apiClientInstance.Port = ep.port + apiClientInstance.AddDefaultHeader( + authorizationHeader, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Username, credentials.Password))))) + v4Client.StorageContainerAPI = storageApi.NewStorageContainerApi(apiClientInstance) + return nil +} + +func getEndpointInfo(credentials prismgoclient.Credentials) (*endpointInfo, error) { + u, err := url.Parse(fmt.Sprintf("https://%s", credentials.Endpoint)) + if err != nil { + return nil, err + } + h := u.Hostname() + port := u.Port() + if port == "" { + port = defaultEndpointPort + } + p, err := strconv.Atoi(port) + if err != nil { + return nil, fmt.Errorf("failed to convert port number to int: %v", err) + } + return &endpointInfo{ + host: h, + port: p, + }, nil +} diff --git a/v4/v4_test.go b/v4/v4_test.go new file mode 100644 index 00000000..c63cb53b --- /dev/null +++ b/v4/v4_test.go @@ -0,0 +1,46 @@ +package v4 + +import ( + "testing" + + prismgoclient "github.com/nutanix-cloud-native/prism-go-client" + "github.com/stretchr/testify/assert" +) + +func TestNewV4Client(t *testing.T) { + // verifies positive client creation + cred := prismgoclient.Credentials{ + URL: "foo.com", + Username: "username", + Password: "password", + Port: "", + Endpoint: "0.0.0.0", + Insecure: true, + FoundationEndpoint: "10.0.0.0", + FoundationPort: "8000", + RequiredFields: nil, + } + v4Client, err := NewV4Client(cred) + assert.NoError(t, err) + assert.NotNil(t, v4Client) + assert.NotNil(t, v4Client.VmApiInstance) + assert.NotNil(t, v4Client.ImagesApiInstance) + assert.NotNil(t, v4Client.SubnetApiInstance) + assert.NotNil(t, v4Client.SubnetReserveUnreserveIPAPIInstance) + assert.NotNil(t, v4Client.ClusterApiInstance) + assert.NotNil(t, v4Client.TasksApiInstance) + assert.NotNil(t, v4Client.StorageContainerAPI) + + // verify missing client scenario + cred = prismgoclient.Credentials{ + URL: "foo.com", + Insecure: true, + RequiredFields: map[string][]string{ + "prism_central": {"username", "password", "endpoint"}, + }, + } + + v4Client, err = NewV4Client(cred) + assert.Nil(t, v4Client) + assert.EqualError(t, err, "username, password and endpoint are required") +}