diff --git a/deploy.go b/deploy.go index cdc0e1d..db6bb1d 100644 --- a/deploy.go +++ b/deploy.go @@ -236,7 +236,10 @@ func (gc *GatewayClient) UploadPackages(filePaths []string) (*types.GatewayRespo if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -304,7 +307,10 @@ func (gc *GatewayClient) ParseCSV(filePath string) (*types.GatewayResponse, erro if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -363,7 +369,10 @@ func (gc *GatewayClient) GetPackageDetails() ([]*types.PackageDetails, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) @@ -385,7 +394,10 @@ func (gc *GatewayClient) GetPackageDetails() ([]*types.PackageDetails, error) { if httpResp.StatusCode == 200 { if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return packageParam, fmt.Errorf("Error While Storing cookie: %s", err) + } } err := json.Unmarshal([]byte(responseString), &packageParam) @@ -411,7 +423,10 @@ func (gc *GatewayClient) ValidateMDMDetails(mdmTopologyParam []byte) (*types.Gat if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -444,7 +459,10 @@ func (gc *GatewayClient) ValidateMDMDetails(mdmTopologyParam []byte) (*types.Gat } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } var mdmTopologyDetails types.MDMTopologyDetails @@ -473,7 +491,10 @@ func (gc *GatewayClient) GetClusterDetails(mdmTopologyParam []byte, requireJSONO if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -506,7 +527,10 @@ func (gc *GatewayClient) GetClusterDetails(mdmTopologyParam []byte, requireJSONO } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } if requireJSONOutput { @@ -544,7 +568,10 @@ func (gc *GatewayClient) DeletePackage(packageName string) (*types.GatewayRespon if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -573,7 +600,10 @@ func (gc *GatewayClient) DeletePackage(packageName string) (*types.GatewayRespon } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -631,7 +661,10 @@ func (gc *GatewayClient) BeginInstallation(jsonStr, mdmUsername, mdmPassword, li if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -677,7 +710,10 @@ func (gc *GatewayClient) MoveToNextPhase() (*types.GatewayResponse, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -707,7 +743,10 @@ func (gc *GatewayClient) MoveToNextPhase() (*types.GatewayResponse, error) { } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -727,7 +766,10 @@ func (gc *GatewayClient) RetryPhase() (*types.GatewayResponse, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -757,7 +799,10 @@ func (gc *GatewayClient) RetryPhase() (*types.GatewayResponse, error) { } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -777,7 +822,10 @@ func (gc *GatewayClient) AbortOperation() (*types.GatewayResponse, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -807,7 +855,10 @@ func (gc *GatewayClient) AbortOperation() (*types.GatewayResponse, error) { } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -827,7 +878,10 @@ func (gc *GatewayClient) ClearQueueCommand() (*types.GatewayResponse, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -857,7 +911,10 @@ func (gc *GatewayClient) ClearQueueCommand() (*types.GatewayResponse, error) { } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -877,7 +934,10 @@ func (gc *GatewayClient) MoveToIdlePhase() (*types.GatewayResponse, error) { if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -907,7 +967,10 @@ func (gc *GatewayClient) MoveToIdlePhase() (*types.GatewayResponse, error) { } if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return &gatewayResponse, fmt.Errorf("Error While Storing cookie: %s", err) + } } gatewayResponse.StatusCode = 200 @@ -927,7 +990,10 @@ func (gc *GatewayClient) GetInQueueCommand() ([]types.MDMQueueCommandDetails, er if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } @@ -947,7 +1013,10 @@ func (gc *GatewayClient) GetInQueueCommand() ([]types.MDMQueueCommandDetails, er if httpResp.StatusCode == 200 { if gc.version == "4.0" { - storeCookie(httpResp.Header, gc.host) + err := storeCookie(httpResp.Header, gc.host) + if err != nil { + return mdmQueueCommandDetails, fmt.Errorf("Error While Storing cookie: %s", err) + } } var queueCommandDetails map[string][]interface{} @@ -1047,7 +1116,10 @@ func (gc *GatewayClient) UninstallCluster(jsonStr, mdmUsername, mdmPassword, lia if gc.version == "4.0" { req.Header.Set("Authorization", "Bearer "+gc.token) - setCookie(req.Header, gc.host) + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } } else { req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } diff --git a/inttests/node_test.go b/inttests/node_test.go index 6be1888..e874f66 100644 --- a/inttests/node_test.go +++ b/inttests/node_test.go @@ -19,47 +19,46 @@ import ( ) func TestGetNodes(t *testing.T) { - allNodes, err := C.GetAllNodes() + allNodes, err := GC.GetAllNodes() assert.Nil(t, err) assert.NotNil(t, allNodes) } func TestGetNodeByID(t *testing.T) { - allNodes, err := C.GetAllNodes() + allNodes, err := GC.GetAllNodes() assert.Nil(t, err) assert.NotNil(t, allNodes) if len(allNodes) > 0 { - node, err := C.GetNodeByID(allNodes[0].RefID) + node, err := GC.GetNodeByID(allNodes[0].RefID) assert.Nil(t, err) assert.NotNil(t, node) } - node, err := C.GetNodeByID(invalidIdentifier) + node, err := GC.GetNodeByID(invalidIdentifier) assert.NotNil(t, err) assert.Nil(t, node) } func TestGetNodeByFilters(t *testing.T) { - allNodes, err := C.GetNodeByFilters("invalid", "invalid") + allNodes, err := GC.GetNodeByFilters("invalid", "invalid") assert.NotNil(t, err) assert.Nil(t, allNodes) } func TestGetNodePoolByID(t *testing.T) { - nodePool, err := C.GetNodePoolByID(-2) - assert.Nil(t, err) - assert.Equal(t, nodePool.DeviceGroup.GroupName, "") + _, err := GC.GetNodePoolByID(-2) + assert.NotNil(t, err) } func TestGetNodePoolByName(t *testing.T) { - nodePool, err := C.GetNodePoolByName(invalidIdentifier) + nodePool, err := GC.GetNodePoolByName(invalidIdentifier) assert.NotNil(t, err) assert.Nil(t, nodePool) } func TestGetAllNodePools(t *testing.T) { - allNodePools, err := C.GetAllNodePools() + allNodePools, err := GC.GetAllNodePools() assert.Nil(t, err) assert.NotNil(t, allNodePools) } diff --git a/inttests/service_test.go b/inttests/service_test.go new file mode 100644 index 0000000..66c6f34 --- /dev/null +++ b/inttests/service_test.go @@ -0,0 +1,59 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package inttests + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDeployeService(t *testing.T) { + _, err := GC.DeployService("Test-Create", "Test", "453c41eb-d72a-4ed1-ad16-bacdffbdd766", "8aaaee208c8c467e018cd37813250614", "3") + assert.NotNil(t, err) +} + +func TestGetAllDeployeService(t *testing.T) { + deployments, err := GC.GetAllServiceDetails() + assert.Nil(t, err) + assert.NotNil(t, deployments) + + if len(deployments) > 0 { + template, err := GC.GetServiceDetailsByID(deployments[0].ID, false) + assert.Nil(t, err) + assert.NotNil(t, template) + + _, err = GC.UpdateService("ABC", "Test-Update-K", "Test-Update-K", "4") + assert.NotNil(t, err) + } + + template, err := GC.GetServiceDetailsByID(invalidIdentifier, false) + assert.NotNil(t, err) + assert.Nil(t, template) +} + +func TestGetDeployeServiceByName(t *testing.T) { + deployments, err := GC.GetAllServiceDetails() + assert.Nil(t, err) + assert.NotNil(t, deployments) + + if len(deployments) > 0 { + template, err := GC.GetServiceDetailsByFilter("name", deployments[0].DeploymentName) + assert.Nil(t, err) + assert.NotNil(t, template) + } + + template, err := GC.GetServiceDetailsByFilter("invalid", "invalid") + assert.NotNil(t, err) + assert.Nil(t, template) +} diff --git a/inttests/template_test.go b/inttests/template_test.go index 41e24ed..5d5cecc 100644 --- a/inttests/template_test.go +++ b/inttests/template_test.go @@ -19,29 +19,29 @@ import ( ) func TestGetTemplates(t *testing.T) { - templates, err := C.GetAllTemplates() + templates, err := GC.GetAllTemplates() assert.Nil(t, err) assert.NotNil(t, templates) } func TestGetTemplateByID(t *testing.T) { - templates, err := C.GetAllTemplates() + templates, err := GC.GetAllTemplates() assert.Nil(t, err) assert.NotNil(t, templates) if len(templates) > 0 { - template, err := C.GetTemplateByID(templates[0].ID) + template, err := GC.GetTemplateByID(templates[0].ID) assert.Nil(t, err) assert.NotNil(t, template) } - template, err := C.GetTemplateByID(invalidIdentifier) + template, err := GC.GetTemplateByID(invalidIdentifier) assert.NotNil(t, err) assert.Nil(t, template) } func TestGetTemplateByFilters(t *testing.T) { - templates, err := C.GetTemplateByFilters("invalid", "invalid") + templates, err := GC.GetTemplateByFilters("name", "invalid") assert.NotNil(t, err) assert.Nil(t, templates) } diff --git a/node.go b/node.go index 4c6762d..3be704b 100644 --- a/node.go +++ b/node.go @@ -13,6 +13,8 @@ package goscaleio import ( + "encoding/base64" + "encoding/json" "errors" "fmt" "net/http" @@ -22,94 +24,252 @@ import ( ) // GetNodeByID gets the node details based on ID -func (c *Client) GetNodeByID(id string) (*types.NodeDetails, error) { +func (gc *GatewayClient) GetNodeByID(id string) (*types.NodeDetails, error) { defer TimeSpent("GetNodeByID", time.Now()) path := fmt.Sprintf("/Api/V1/ManagedDevice/%v", id) var node types.NodeDetails - err := c.getJSONWithRetry(http.MethodGet, path, nil, &node) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &node) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Node: %s", parseError) + } + } else { + return nil, fmt.Errorf("Couldn't find nodes with the given filter") } return &node, nil } // GetAllNodes gets all the node details -func (c *Client) GetAllNodes() ([]types.NodeDetails, error) { +func (gc *GatewayClient) GetAllNodes() ([]types.NodeDetails, error) { defer TimeSpent("GetNodeByID", time.Now()) path := fmt.Sprintf("/Api/V1/ManagedDevice") var nodes []types.NodeDetails - err := c.getJSONWithRetry(http.MethodGet, path, nil, &nodes) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &nodes) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Node: %s", parseError) + } + } else { + return nil, fmt.Errorf("Couldn't find nodes with the given filter") } return nodes, nil } // GetNodeByFilters gets the node details based on the provided filter -func (c *Client) GetNodeByFilters(key string, value string) ([]types.NodeDetails, error) { +func (gc *GatewayClient) GetNodeByFilters(key string, value string) ([]types.NodeDetails, error) { defer TimeSpent("GetNodeByFilters", time.Now()) path := fmt.Sprintf("/Api/V1/ManagedDevice?filter=eq,%v,%v", key, value) var nodes []types.NodeDetails - err := c.getJSONWithRetry(http.MethodGet, path, nil, &nodes) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError } - if len(nodes) == 0 { - return nil, errors.New("Couldn't find nodes with the given filter") + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &nodes) + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Node: %s", parseError) + } + + if len(nodes) == 0 { + return nil, errors.New("Couldn't find nodes with the given filter") + } + } else { + return nil, fmt.Errorf("Couldn't find nodes with the given filter") } return nodes, nil } // GetNodePoolByID gets the nodepool details based on ID -func (c *Client) GetNodePoolByID(id int) (*types.NodePoolDetails, error) { +func (gc *GatewayClient) GetNodePoolByID(id int) (*types.NodePoolDetails, error) { defer TimeSpent("GetNodePoolByID", time.Now()) path := fmt.Sprintf("/Api/V1/nodepool/%v", id) var nodePool types.NodePoolDetails - err := c.getJSONWithRetry(http.MethodGet, path, nil, &nodePool) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 && responseString != "" { + parseError := json.Unmarshal([]byte(responseString), &nodePool) + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Nodepool: %s", parseError) + } + + } else { + return nil, fmt.Errorf("Couldn't find nodes with the given filter") } return &nodePool, nil } // GetNodePoolByName gets the nodepool details based on name -func (c *Client) GetNodePoolByName(name string) (*types.NodePoolDetails, error) { +func (gc *GatewayClient) GetNodePoolByName(name string) (*types.NodePoolDetails, error) { defer TimeSpent("GetNodePoolByName", time.Now()) - nodePools, err := c.GetAllNodePools() + nodePools, err := gc.GetAllNodePools() if err != nil { return nil, err } for _, nodePool := range nodePools.NodePoolDetails { if nodePool.GroupName == name { - return c.GetNodePoolByID(nodePool.GroupSeqID) + return gc.GetNodePoolByID(nodePool.GroupSeqID) } } return nil, errors.New("no node pool found with name " + name) } // GetAllNodePools gets all the nodepool details -func (c *Client) GetAllNodePools() (*types.NodePoolDetailsFilter, error) { +func (gc *GatewayClient) GetAllNodePools() (*types.NodePoolDetailsFilter, error) { defer TimeSpent("GetAllNodePools", time.Now()) path := fmt.Sprintf("/Api/V1/nodepool") var nodePools types.NodePoolDetailsFilter - err := c.getJSONWithRetry(http.MethodGet, path, nil, &nodePools) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError } + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &nodePools) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Nodepool: %s", parseError) + } + } else { + return nil, fmt.Errorf("Couldn't find nodes with the given filter") + } return &nodePools, nil } diff --git a/node_test.go b/node_test.go index 77a8916..99755b7 100644 --- a/node_test.go +++ b/node_test.go @@ -15,7 +15,6 @@ package goscaleio import ( "errors" "fmt" - "math" "net/http" "net/http/httptest" "testing" @@ -29,8 +28,8 @@ func TestGetNodes(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -64,7 +63,8 @@ func TestGetNodeByID(t *testing.T) { for _, tc := range cases { tc := tc t.Run("", func(ts *testing.T) { - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -107,7 +107,8 @@ func TestGetNodePoolByID(t *testing.T) { for _, tc := range cases { tc := tc t.Run("", func(ts *testing.T) { - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -132,8 +133,8 @@ func TestGetNodeByFilters(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -149,8 +150,8 @@ func TestGetNodePoolByName(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -167,8 +168,8 @@ func TestGetNodePoolByNameError(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -185,8 +186,8 @@ func TestGetNodePoolByIDNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -203,8 +204,8 @@ func TestGetNodeByIDNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -221,8 +222,8 @@ func TestGetAllNodesNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } diff --git a/service.go b/service.go new file mode 100644 index 0000000..5c3bee8 --- /dev/null +++ b/service.go @@ -0,0 +1,713 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goscaleio + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "time" + + types "github.com/dell/goscaleio/types/v1" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" +) + +// DeployService used to deploy service +func (gc *GatewayClient) DeployService(deploymentName, deploymentDesc, serviceTemplateID, firmwareRepositoryID, nodes string) (*types.ServiceResponse, error) { + defer TimeSpent("DeployService", time.Now()) + + path := fmt.Sprintf("/Api/V1/FirmwareRepository/%v", firmwareRepositoryID) + + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 && responseString == "" { + return nil, fmt.Errorf("Firmware Repository Not Found") + } + + path = fmt.Sprintf("/Api/V1/ServiceTemplate/%v?forDeployment=true", serviceTemplateID) + + req, httpError = http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client = gc.http + httpResp, httpRespError = client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ = extractString(httpResp) + + if httpResp.StatusCode == 200 && responseString != "" { + var templateData map[string]interface{} + + parseError := json.Unmarshal([]byte(responseString), &templateData) + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Template: %s", parseError) + } + + configuredNode, _ := templateData["serverCount"].(int) + + nodes, _ := strconv.Atoi(nodes) + + if nodes > 0 { + nodeDiff := nodes - configuredNode + + if nodeDiff != 0 { + return nil, fmt.Errorf("Node count is not matching with Service Template") + } + } + + deploymentPayload := map[string]interface{}{ + "deploymentName": deploymentName, + "deploymentDescription": deploymentDesc, + "serviceTemplate": templateData, + "updateServerFirmware": true, + "firmwareRepositoryId": firmwareRepositoryID, //TODO + } + + deploymentPayloadJson, _ := json.Marshal(deploymentPayload) + + req, httpError := http.NewRequest("POST", gc.host+"/Api/V1/Deployment", bytes.NewBuffer(deploymentPayloadJson)) + if httpError != nil { + return nil, httpError + } + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, error := extractString(httpResp) + if error != nil { + return nil, fmt.Errorf("Error Extracting Response: %s", error) + } + + if httpResp.StatusCode == 200 { + + var deploymentResponse types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + deploymentResponse.StatusCode = 200 + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return &deploymentResponse, nil + + } else { + var deploymentResponse types.ServiceFailedResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + deploymentResponse.StatusCode = 400 + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", deploymentResponse.Messages[0].DisplayMessage) + } + + } else { + return nil, fmt.Errorf("Service Template Not Found") + } +} + +func (gc *GatewayClient) UpdateService(deploymentID, deploymentName, deploymentDesc, nodes string) (*types.ServiceResponse, error) { + defer TimeSpent("UpdateService", time.Now()) + + path := fmt.Sprintf("/Api/V1/Deployment/%v", deploymentID) + + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 && responseString != "" { + + var deploymentResponse types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + deployedNodes := deploymentResponse.ServiceTemplate.ServerCount + + var deploymentPayloadJson []byte + + nodes, _ := strconv.Atoi(nodes) + + nodeDiff := nodes - deployedNodes + + if nodeDiff > 0 && nodeDiff == 1 { + + var deploymentData map[string]interface{} + + uuid := uuid.New().String() + + parseError := json.Unmarshal([]byte(responseString), &deploymentData) + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + deploymentData["deploymentName"] = deploymentName + + deploymentData["deploymentDescription"] = deploymentDesc + + // Access the "components" field + serviceTemplate, ok := deploymentData["serviceTemplate"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment") + } + + components, ok := serviceTemplate["components"].([]interface{}) + if !ok { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment") + } + + // Find the component with type "SERVER" + var serverComponent map[string]interface{} + + for _, comp := range components { + comp := comp.(map[string]interface{}) + if comp["type"].(string) == "SERVER" { + serverComponent = comp + break + } + } + + // Deep copy the component + clonedComponent := make(map[string]interface{}) + for key, value := range serverComponent { + clonedComponent[key] = value + } + + // Modify ID and GUID of the cloned component + clonedComponent["id"] = uuid + clonedComponent["name"] = uuid + clonedComponent["brownfield"] = false + + clonedComponent["identifier"] = nil + clonedComponent["asmGUID"] = nil + clonedComponent["puppetCertName"] = nil + clonedComponent["osPuppetCertName"] = nil + clonedComponent["managementIpAddress"] = nil + + // Deep copy resources + resources, ok := clonedComponent["resources"].([]interface{}) + if !ok { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment") + } + + clonedResources := make([]interface{}, len(resources)) + for i, res := range resources { + resCopy := make(map[string]interface{}) + for k, v := range res.(map[string]interface{}) { + resCopy[k] = v + } + clonedResources[i] = resCopy + } + clonedComponent["resources"] = clonedResources + + // Exclude list of parameters to skip + excludeList := map[string]bool{ + "razor_image": true, + "scaleio_enabled": true, + "scaleio_role": true, + "compression_enabled": true, + "replication_enabled": true, + } + + // Iterate over resources to modify parameters + for _, comp := range clonedResources { + comp := comp.(map[string]interface{}) + if comp["id"].(string) == "asm::server" { + + comp["guid"] = nil + + parameters, ok := comp["parameters"].([]interface{}) + if !ok { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment") + } + + clonedParams := make([]interface{}, len(parameters)) + for i, param := range parameters { + paramCopy := make(map[string]interface{}) + for k, v := range param.(map[string]interface{}) { + paramCopy[k] = v + } + clonedParams[i] = paramCopy + } + + for _, parameter := range clonedParams { + parameter := parameter.(map[string]interface{}) + if !excludeList[parameter["id"].(string)] { + + if parameter["id"].(string) == "scaleio_mdm_role" { + parameter["guid"] = nil + parameter["value"] = "standby_mdm" + } else { + parameter["guid"] = nil + parameter["value"] = nil + } + + } + } + + // Update parameters in the component + comp["parameters"] = clonedParams + } + } + + // Append the cloned component back to the components array + components = append(components, clonedComponent) + + // Update serviceTemplate with modified components + serviceTemplate["components"] = components + + // Update deploymentData with modified serviceTemplate + deploymentData["serviceTemplate"] = serviceTemplate + + // Update other fields as needed + deploymentData["scaleUp"] = true + deploymentData["retry"] = true + + // Marshal deploymentData to JSON + deploymentPayloadJson, _ = json.Marshal(deploymentData) + + } else if nodeDiff == 0 { + + deploymentResponse, jsonParseError := jsonToMap(responseString) + if jsonParseError != nil { + return nil, jsonParseError + } + + deploymentResponse["deploymentName"] = deploymentName + + deploymentResponse["deploymentDescription"] = deploymentDesc + + deploymentPayloadJson, _ = json.Marshal(deploymentResponse) + } else if nodeDiff > 1 || nodeDiff < 0 { + return nil, fmt.Errorf("node difference is more than 1") + } + + req, httpError := http.NewRequest("PUT", gc.host+"/Api/V1/Deployment/"+deploymentID, bytes.NewBuffer(deploymentPayloadJson)) + if httpError != nil { + return nil, httpError + } + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, error := extractString(httpResp) + if error != nil { + return nil, fmt.Errorf("Error Extracting Response: %s", error) + } + + if httpResp.StatusCode == 200 { + + var deploymentResponse types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + deploymentResponse.StatusCode = 200 + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return &deploymentResponse, nil + + } else { + var deploymentResponse types.ServiceFailedResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + deploymentResponse.StatusCode = 400 + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", deploymentResponse.Messages[0].DisplayMessage) + } + + } else { + var deploymentResponse types.ServiceFailedResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", deploymentResponse.Messages[0].DisplayMessage) + } +} + +// Function to check if string is not present in list +func contains(list []string, str string) bool { + for _, s := range list { + if s == str { + return true + } + } + return false +} + +func (gc *GatewayClient) GetServiceDetailsByID(deploymentID string, newToken bool) (*types.ServiceResponse, error) { + + defer TimeSpent("GetServiceDetailsByID", time.Now()) + + if newToken { + bodyData := map[string]interface{}{ + "username": gc.username, + "password": gc.password, + } + + body, _ := json.Marshal(bodyData) + + req, err := http.NewRequest("POST", gc.host+"/rest/auth/login", bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", "application/json") + + resp, err := gc.http.Do(req) + if err != nil { + return nil, err + } + + defer func() { + if err := resp.Body.Close(); err != nil { + doLog(log.WithError(err).Error, "") + } + }() + + // parse the response + switch { + case resp == nil: + return nil, errNilReponse + case !(resp.StatusCode >= 200 && resp.StatusCode <= 299): + return nil, gc.api.ParseJSONError(resp) + } + + bs, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + responseBody := string(bs) + + result := make(map[string]interface{}) + jsonErr := json.Unmarshal([]byte(responseBody), &result) + if err != nil { + return nil, fmt.Errorf("Error For Uploading Package: %s", jsonErr) + } + + token := result["access_token"].(string) + + gc.token = token + } + + path := fmt.Sprintf("/Api/V1/Deployment/%v", deploymentID) + + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + + var deploymentResponse types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return &deploymentResponse, nil + + } else { + return nil, fmt.Errorf("Couldn't find service with the given filter") + } +} + +func (gc *GatewayClient) GetServiceDetailsByFilter(filter, value string) ([]types.ServiceResponse, error) { + + defer TimeSpent("GetServiceDetailsByFilter", time.Now()) + + encodedValue := url.QueryEscape(value) + + path := fmt.Sprintf("/Api/V1/Deployment?filter=eq,%v,%v", filter, encodedValue) + + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + + var deploymentResponse []types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + if len(deploymentResponse) == 0 { + return nil, fmt.Errorf("Couldn't find service with the given filter") + } + + return deploymentResponse, nil + + } else { + return nil, fmt.Errorf("Couldn't find service with the given filter") + } +} + +func (gc *GatewayClient) GetAllServiceDetails() ([]types.ServiceResponse, error) { + + defer TimeSpent("DeploGetServiceDetailsByIDyService", time.Now()) + + req, httpError := http.NewRequest("GET", gc.host+"/Api/V1/Deployment/", nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + + var deploymentResponse []types.ServiceResponse + + parseError := json.Unmarshal([]byte(responseString), &deploymentResponse) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Deployment: %s", parseError) + } + + return deploymentResponse, nil + + } else { + return nil, fmt.Errorf("Couldn't find service with the given filter") + } +} + +func (gc *GatewayClient) DeleteService(serviceId string) (*types.ServiceResponse, error) { + + var deploymentResponse types.ServiceResponse + + deploymentResponse.StatusCode = 400 + + defer TimeSpent("DeleteService", time.Now()) + + req, httpError := http.NewRequest("DELETE", gc.host+"/Api/V1/Deployment/"+serviceId+"?serversInInventory=remove&resourceState=managed", nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + if httpResp.StatusCode == 204 { + + deploymentResponse.StatusCode = 200 + + return &deploymentResponse, nil + } + + return nil, fmt.Errorf("Couldn't delete service") +} diff --git a/service_test.go b/service_test.go new file mode 100644 index 0000000..38ed2ae --- /dev/null +++ b/service_test.go @@ -0,0 +1,149 @@ +// Copyright © 2024 Dell Inc. or its subsidiaries. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package goscaleio + +import ( + "errors" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetAllDeployeService(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + })) + defer svr.Close() + + GC, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + templateDetails, err := GC.GetAllServiceDetails() + assert.Equal(t, len(templateDetails), 0) + assert.Nil(t, err) +} + +func TestGetDeployeServiceByID(t *testing.T) { + type testCase struct { + id string + expected error + } + + cases := []testCase{ + { + id: "sdnasgw", + expected: nil, + }, + { + id: "sdnasgw1", + expected: errors.New("The template cannot be found"), + }, + } + + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + GC, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + _, err = GC.GetServiceDetailsByID(tc.id,false) + if err != nil { + if tc.expected == nil { + t.Errorf("Getting template by ID did not work as expected, \n\tgot: %s \n\twant: %v", err, tc.expected) + } else { + if err.Error() != tc.expected.Error() { + t.Errorf("Getting template by ID did not work as expected, \n\tgot: %s \n\twant: %s", err, tc.expected) + } + } + } + }) + } +} + +func TestGetDeployeServiceByFilters(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + })) + defer svr.Close() + + client, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + templates, err := client.GetServiceDetailsByFilter("Name", "Test") + assert.Equal(t, len(templates), 0) + assert.NotNil(t, err) +} + +func TestGetDeployeServiceByIDNegative(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintln(w, `{"error":"Internal Server Error"}`) + })) + defer svr.Close() + + client, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + templates, err := client.GetServiceDetailsByID("Test",false) + assert.Nil(t, templates) + assert.NotNil(t, err) +} + +func TestGetDeployeServiceByFiltersNegative(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintln(w, `{"error":"Internal Server Error"}`) + })) + defer svr.Close() + + client, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + templates, err := client.GetServiceDetailsByFilter("Name", "Test") + assert.Nil(t, templates) + assert.NotNil(t, err) +} + +func TestGetAllDeployeServiceNegative(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintln(w, `{"error":"Internal Server Error"}`) + })) + defer svr.Close() + + client, err := NewGateway(svr.URL, "", "", true, true) + if err != nil { + t.Fatal(err) + } + + templates, err := client.GetAllServiceDetails() + assert.Nil(t, templates) + assert.NotNil(t, err) +} diff --git a/template.go b/template.go index 02e98ea..df9d4cb 100644 --- a/template.go +++ b/template.go @@ -13,7 +13,8 @@ package goscaleio import ( - "errors" + "encoding/base64" + "encoding/json" "fmt" "net/http" "net/url" @@ -23,35 +24,99 @@ import ( ) // GetTemplateByID gets the node details based on ID -func (c *Client) GetTemplateByID(id string) (*types.TemplateDetails, error) { +func (gc *GatewayClient) GetTemplateByID(id string) (*types.TemplateDetails, error) { defer TimeSpent("GetTemplateByID", time.Now()) path := fmt.Sprintf("/Api/V1/template/%v", id) var template types.TemplateDetails - err := c.getJSONWithRetry(http.MethodGet, path, nil, &template) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &template) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Template: %s", parseError) + } + + return &template, nil + } else { + return nil, fmt.Errorf("Template not found") } - return &template, nil } // GetAllTemplates gets all the Template details -func (c *Client) GetAllTemplates() ([]types.TemplateDetails, error) { +func (gc *GatewayClient) GetAllTemplates() ([]types.TemplateDetails, error) { defer TimeSpent("GetAllTemplates", time.Now()) path := fmt.Sprintf("/Api/V1/template") var templates types.TemplateDetailsFilter - err := c.getJSONWithRetry(http.MethodGet, path, nil, &templates) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) + } + + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError + } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &templates) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Template: %s", parseError) + } } + return templates.TemplateDetails, nil } // GetTemplateByFilters gets the Template details based on the provided filter -func (c *Client) GetTemplateByFilters(key string, value string) ([]types.TemplateDetails, error) { +func (gc *GatewayClient) GetTemplateByFilters(key string, value string) ([]types.TemplateDetails, error) { defer TimeSpent("GetTemplateByFilters", time.Now()) encodedValue := url.QueryEscape(value) @@ -59,13 +124,47 @@ func (c *Client) GetTemplateByFilters(key string, value string) ([]types.Templat path := `/Api/V1/template?filter=` + key + `%20eq%20%22` + encodedValue + `%22` var templates types.TemplateDetailsFilter - err := c.getJSONWithRetry(http.MethodGet, path, nil, &templates) - if err != nil { - return nil, err + req, httpError := http.NewRequest("GET", gc.host+path, nil) + if httpError != nil { + return nil, httpError + } + + if gc.version == "4.0" { + req.Header.Set("Authorization", "Bearer "+gc.token) + + err := setCookie(req.Header, gc.host) + if err != nil { + return nil, fmt.Errorf("Error While Handling Cookie: %s", err) + } + + } else { + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(gc.username+":"+gc.password))) } - if len(templates.TemplateDetails) == 0 { - return nil, errors.New("Couldn't find templates with the given filter") + req.Header.Set("Content-Type", "application/json") + + client := gc.http + httpResp, httpRespError := client.Do(req) + if httpRespError != nil { + return nil, httpRespError } + + responseString, _ := extractString(httpResp) + + if httpResp.StatusCode == 200 { + parseError := json.Unmarshal([]byte(responseString), &templates) + + if parseError != nil { + return nil, fmt.Errorf("Error While Parsing Response Data For Template: %s", parseError) + } + + if len(templates.TemplateDetails) == 0 { + return nil, fmt.Errorf("Template not found") + } + + } else { + return nil, fmt.Errorf("Template not found") + } + return templates.TemplateDetails, nil } diff --git a/template_test.go b/template_test.go index e7a5159..0578605 100644 --- a/template_test.go +++ b/template_test.go @@ -15,7 +15,6 @@ package goscaleio import ( "errors" "fmt" - "math" "net/http" "net/http/httptest" "testing" @@ -29,8 +28,8 @@ func TestGetTemplates(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -64,7 +63,8 @@ func TestGetTemplateByID(t *testing.T) { for _, tc := range cases { tc := tc t.Run("", func(ts *testing.T) { - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -89,8 +89,8 @@ func TestGetTemplateByFilters(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -107,8 +107,8 @@ func TestGetTemplateByIDNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -125,8 +125,8 @@ func TestGetTemplateByFiltersNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } @@ -143,8 +143,8 @@ func TestGetAllTemplatesNegative(t *testing.T) { })) defer svr.Close() - client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) - client.configConnect.Version = "4.5" + client, err := NewGateway(svr.URL, "", "", true, false) + client.version = "4.5" if err != nil { t.Fatal(err) } diff --git a/types/v1/serviceTypes.go b/types/v1/serviceTypes.go new file mode 100644 index 0000000..3a23b2d --- /dev/null +++ b/types/v1/serviceTypes.go @@ -0,0 +1,90 @@ +package goscaleio + +type ServiceFailedResponse struct { + DetailMessage string `json:"detailMessage,omitempty"` + Status int `json:"status,omitempty"` + StatusCode int `json:"statusCode,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + Error string `json:"error,omitempty"` + Path string `json:"path,omitempty"` + Messages []Messages `json:"messages,omitempty"` +} + +type DeploymentPayload struct { + DeploymentName string `json:"deploymentName,omitempty"` + DeploymentDescription string `json:"deploymentDescription,omitempty"` + ServiceTemplate TemplateDetails `json:"serviceTemplate,omitempty"` + UpdateServerFirmware bool `json:"updateServerFirmware,omitempty"` + FirmwareRepositoryID string `json:"firmwareRepositoryId,omitempty"` + Status string `json:"status,omitempty"` +} + +type ServiceResponse struct { + ID string `json:"id,omitempty"` + DeploymentName string `json:"deploymentName,omitempty"` + DeploymentDescription string `json:"deploymentDescription,omitempty"` + DeploymentValid DeploymentValid `json:"deploymentValid,omitempty"` + Retry bool `json:"retry,omitempty"` + Teardown bool `json:"teardown,omitempty"` + TeardownAfterCancel bool `json:"teardownAfterCancel,omitempty"` + RemoveService bool `json:"removeService,omitempty"` + CreatedDate string `json:"createdDate,omitempty"` + CreatedBy string `json:"createdBy,omitempty"` + UpdatedDate string `json:"updatedDate,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + DeploymentScheduledDate string `json:"deploymentScheduledDate,omitempty"` + DeploymentStartedDate string `json:"deploymentStartedDate,omitempty"` + DeploymentFinishedDate string `json:"deploymentFinishedDate,omitempty"` + ServiceTemplate TemplateDetails `json:"serviceTemplate"` + ScheduleDate string `json:"scheduleDate,omitempty"` + Status string `json:"status,omitempty"` + Compliant bool `json:"compliant,omitempty"` + DeploymentDevice []DeploymentDevice `json:"deploymentDevice,omitempty"` + Vms []Vms `json:"vms,omitempty"` + UpdateServerFirmware bool `json:"updateServerFirmware,omitempty"` + UseDefaultCatalog bool `json:"useDefaultCatalog,omitempty"` + FirmwareRepository FirmwareRepository `json:"firmwareRepository,omitempty"` + FirmwareRepositoryID string `json:"firmwareRepositoryId,omitempty"` + LicenseRepository LicenseRepository `json:"licenseRepository,omitempty"` + LicenseRepositoryID string `json:"licenseRepositoryId,omitempty"` + IndividualTeardown bool `json:"individualTeardown,omitempty"` + DeploymentHealthStatusType string `json:"deploymentHealthStatusType,omitempty"` + AssignedUsers []AssignedUsers `json:"assignedUsers,omitempty"` + AllUsersAllowed bool `json:"allUsersAllowed,omitempty"` + Owner string `json:"owner,omitempty"` + NoOp bool `json:"noOp,omitempty"` + FirmwareInit bool `json:"firmwareInit,omitempty"` + DisruptiveFirmware bool `json:"disruptiveFirmware,omitempty"` + PreconfigureSVM bool `json:"preconfigureSVM,omitempty"` + PreconfigureSVMAndUpdate bool `json:"preconfigureSVMAndUpdate,omitempty"` + ServicesDeployed string `json:"servicesDeployed,omitempty"` + PrecalculatedDeviceHealth string `json:"precalculatedDeviceHealth,omitempty"` + LifecycleModeReasons []string `json:"lifecycleModeReasons,omitempty"` + JobDetails []JobDetails `json:"jobDetails,omitempty"` + NumberOfDeployments int `json:"numberOfDeployments,omitempty"` + OperationType string `json:"operationType,omitempty"` + OperationStatus string `json:"operationStatus,omitempty"` + OperationData string `json:"operationData,omitempty"` + DeploymentValidationResponse DeploymentValidationResponse `json:"deploymentValidationResponse,omitempty"` + CurrentStepCount string `json:"currentStepCount,omitempty"` + TotalNumOfSteps string `json:"totalNumOfSteps,omitempty"` + CurrentStepMessage string `json:"currentStepMessage,omitempty"` + CustomImage string `json:"customImage,omitempty"` + OriginalDeploymentID string `json:"originalDeploymentId,omitempty"` + CurrentBatchCount string `json:"currentBatchCount,omitempty"` + TotalBatchCount string `json:"totalBatchCount,omitempty"` + Brownfield bool `json:"brownfield,omitempty"` + OverallDeviceHealth string `json:"overallDeviceHealth,omitempty"` + Vds bool `json:"vds,omitempty"` + ScaleUp bool `json:"scaleUp,omitempty"` + LifecycleMode bool `json:"lifecycleMode,omitempty"` + CanMigratevCLSVMs bool `json:"canMigratevCLSVMs,omitempty"` + TemplateValid bool `json:"templateValid,omitempty"` + ConfigurationChange bool `json:"configurationChange,omitempty"` + DetailMessage string `json:"detailMessage,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + Error string `json:"error,omitempty"` + Path string `json:"path,omitempty"` + Messages []Messages `json:"messages,omitempty"` + StatusCode int `json:"statusCode,omitempty"` +} diff --git a/types/v1/templateTypes.go b/types/v1/templateTypes.go index ed87085..86e1f2d 100644 --- a/types/v1/templateTypes.go +++ b/types/v1/templateTypes.go @@ -13,40 +13,40 @@ package goscaleio type TemplateDetails struct { - ID string `json:"id,omitempty"` - TemplateName string `json:"templateName,omitempty"` - TemplateDescription string `json:"templateDescription,omitempty"` - TemplateType string `json:"templateType,omitempty"` - TemplateVersion string `json:"templateVersion,omitempty"` - OriginalTemplateID string `json:"originalTemplateId,omitempty"` - TemplateValid TemplateValid `json:"templateValid,omitempty"` - TemplateLocked bool `json:"templateLocked,omitempty"` - InConfiguration bool `json:"inConfiguration,omitempty"` - CreatedDate string `json:"createdDate,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` - UpdatedDate string `json:"updatedDate,omitempty"` - LastDeployedDate string `json:"lastDeployedDate,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - ManageFirmware bool `json:"manageFirmware,omitempty"` - UseDefaultCatalog bool `json:"useDefaultCatalog,omitempty"` - FirmwareRepository FirmwareRepository `json:"firmwareRepository,omitempty"` - LicenseRepository LicenseRepository `json:"licenseRepository,omitempty"` - AssignedUsers []AssignedUsers `json:"assignedUsers,omitempty"` - AllUsersAllowed bool `json:"allUsersAllowed,omitempty"` - Category string `json:"category,omitempty"` - Components []Components `json:"components,omitempty"` - Configuration ConfigurationDetails `json:"configuration,omitempty"` - ServerCount int `json:"serverCount,omitempty"` - StorageCount int `json:"storageCount,omitempty"` - ClusterCount int `json:"clusterCount,omitempty"` - ServiceCount int `json:"serviceCount,omitempty"` - SwitchCount int `json:"switchCount,omitempty"` - VMCount int `json:"vmCount,omitempty"` - SdnasCount int `json:"sdnasCount,omitempty"` - BrownfieldTemplateType string `json:"brownfieldTemplateType,omitempty"` - Networks []Networks `json:"networks,omitempty"` - BlockServiceOperationsMap BlockServiceOperationsMap `json:"blockServiceOperationsMap,omitempty"` - Draft bool `json:"draft,omitempty"` + ID string `json:"id,omitempty"` + TemplateName string `json:"templateName,omitempty"` + TemplateDescription string `json:"templateDescription,omitempty"` + TemplateType string `json:"templateType,omitempty"` + TemplateVersion string `json:"templateVersion,omitempty"` + OriginalTemplateID string `json:"originalTemplateId,omitempty"` + TemplateValid TemplateValid `json:"templateValid,omitempty"` + TemplateLocked bool `json:"templateLocked,omitempty"` + InConfiguration bool `json:"inConfiguration,omitempty"` + CreatedDate string `json:"createdDate,omitempty"` + CreatedBy string `json:"createdBy,omitempty"` + UpdatedDate string `json:"updatedDate,omitempty"` + LastDeployedDate string `json:"lastDeployedDate,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + ManageFirmware bool `json:"manageFirmware,omitempty"` + UseDefaultCatalog bool `json:"useDefaultCatalog,omitempty"` + FirmwareRepository FirmwareRepository `json:"firmwareRepository,omitempty"` + LicenseRepository LicenseRepository `json:"licenseRepository,omitempty"` + AssignedUsers []AssignedUsers `json:"assignedUsers,omitempty"` + AllUsersAllowed bool `json:"allUsersAllowed,omitempty"` + Category string `json:"category,omitempty"` + Components []Components `json:"components,omitempty"` + Configuration ConfigurationDetails `json:"configuration,omitempty"` + ServerCount int `json:"serverCount,omitempty"` + StorageCount int `json:"storageCount,omitempty"` + ClusterCount int `json:"clusterCount,omitempty"` + ServiceCount int `json:"serviceCount,omitempty"` + SwitchCount int `json:"switchCount,omitempty"` + VMCount int `json:"vmCount,omitempty"` + SdnasCount int `json:"sdnasCount,omitempty"` + BrownfieldTemplateType string `json:"brownfieldTemplateType,omitempty"` + Networks []Networks `json:"networks,omitempty"` + NetworksMap map[string]Networks `json:"networksMap,omitempty"` + Draft bool `json:"draft,omitempty"` } type Messages struct { @@ -402,16 +402,14 @@ type NetworkConfiguration struct { } type ConfigurationDetails struct { - ID string `json:"id,omitempty"` - Disktype string `json:"disktype,omitempty"` - Comparator string `json:"comparator,omitempty"` - Numberofdisks int `json:"numberofdisks,omitempty"` - Raidlevel string `json:"raidlevel,omitempty"` - VirtualDiskFqdd string `json:"virtualDiskFqdd,omitempty"` - ControllerFqdd string `json:"controllerFqdd,omitempty"` - Categories []Categories `json:"categories,omitempty"` - CategoriesMap CategoriesMap `json:"categoriesMap,omitempty"` - SettingsMap SettingsMap `json:"settingsMap,omitempty"` + ID string `json:"id,omitempty"` + Disktype string `json:"disktype,omitempty"` + Comparator string `json:"comparator,omitempty"` + Numberofdisks int `json:"numberofdisks,omitempty"` + Raidlevel string `json:"raidlevel,omitempty"` + VirtualDiskFqdd string `json:"virtualDiskFqdd,omitempty"` + ControllerFqdd string `json:"controllerFqdd,omitempty"` + Categories []Categories `json:"categories,omitempty"` } type VirtualDisks struct { @@ -899,34 +897,11 @@ type Parameters struct { OptionsSortable bool `json:"optionsSortable,omitempty"` } -type ParameterMap struct { - AdditionalProp1 AdditionalPropDetails `json:"additionalProp1,omitempty"` - AdditionalProp2 AdditionalPropDetails `json:"additionalProp2,omitempty"` - AdditionalProp3 AdditionalPropDetails `json:"additionalProp3,omitempty"` -} type Categories struct { - ID string `json:"id,omitempty"` - DisplayName string `json:"displayName,omitempty"` - DeviceType string `json:"deviceType,omitempty"` - Parameters []Parameters `json:"parameters,omitempty"` - ParameterMap ParameterMap `json:"parameterMap,omitempty"` -} - -type CategoriesMap struct { - AdditionalProp1 AdditionalPropDetails `json:"additionalProp1,omitempty"` - AdditionalProp2 AdditionalPropDetails `json:"additionalProp2,omitempty"` - AdditionalProp3 AdditionalPropDetails `json:"additionalProp3,omitempty"` -} -type SettingsMap struct { - AdditionalProp1 AdditionalPropDetails `json:"additionalProp1,omitempty"` - AdditionalProp2 AdditionalPropDetails `json:"additionalProp2,omitempty"` - AdditionalProp3 AdditionalPropDetails `json:"additionalProp3,omitempty"` -} - -type BlockServiceOperationsMap struct { - AdditionalProp1 AdditionalPropDetails `json:"additionalProp1,omitempty"` - AdditionalProp2 AdditionalPropDetails `json:"additionalProp2,omitempty"` - AdditionalProp3 AdditionalPropDetails `json:"additionalProp3,omitempty"` + ID string `json:"id,omitempty"` + DisplayName string `json:"displayName,omitempty"` + DeviceType string `json:"deviceType,omitempty"` + Parameters []Parameters `json:"parameters,omitempty"` } // TemplateDetailsFilter defines struct for nodepools