Skip to content

Commit

Permalink
Support 4.x compatibility (#23)
Browse files Browse the repository at this point in the history
* handle type compatibilty for 4.x baseline

* fix CSLong to be more permissive and add unit test

* Rename CSLong to UUID

Co-authored-by: Xavier MARCELET <[email protected]>
  • Loading branch information
davidjumani and psycofdj committed Nov 29, 2021
1 parent 3d07af9 commit 71cd5ea
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 9 deletions.
18 changes: 9 additions & 9 deletions cloudstack/HostService.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ type AddBaremetalHostResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -789,7 +789,7 @@ type AddHostResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -1032,7 +1032,7 @@ type CancelHostMaintenanceResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -1830,7 +1830,7 @@ type FindHostsForMigrationResponse struct {
JobID string `json:"jobid"`
Jobstatus int `json:"jobstatus"`
Lastpinged string `json:"lastpinged"`
Managementserverid int64 `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated string `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -2645,7 +2645,7 @@ type Host struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -3167,7 +3167,7 @@ type HostsMetric struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocateddisablethreshold bool `json:"memoryallocateddisablethreshold"`
Expand Down Expand Up @@ -3331,7 +3331,7 @@ type PrepareHostForMaintenanceResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -3485,7 +3485,7 @@ type ReconnectHostResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down Expand Up @@ -3880,7 +3880,7 @@ type UpdateHostResponse struct {
Jobstatus int `json:"jobstatus"`
Lastannotated string `json:"lastannotated"`
Lastpinged string `json:"lastpinged"`
Managementserverid string `json:"managementserverid"`
Managementserverid UUID `json:"managementserverid"`
Memoryallocated int64 `json:"memoryallocated"`
Memoryallocatedbytes int64 `json:"memoryallocatedbytes"`
Memoryallocatedpercentage string `json:"memoryallocatedpercentage"`
Expand Down
2 changes: 2 additions & 0 deletions cloudstack/HostService_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func TestHostService_PrepareHostForMaintenance(t *testing.T) {
resp, err := client.Host.PrepareHostForMaintenance(params)
if err != nil {
t.Errorf("Failed to prepare host for maintenance due to: %v", err)
return
}
if resp.Resourcestate != "PrepareForMaintenance" {
t.Errorf("Failed to prepare host for maintenance")
Expand All @@ -109,6 +110,7 @@ func TestHostService_CancelHostForMaintenance(t *testing.T) {
resp, err := client.Host.CancelHostMaintenance(params)
if err != nil {
t.Errorf("Failed to cancel host for maintenance due to: %v", err)
return
}
if resp.Resourcestate != "Enabled" {
t.Errorf("Failed to cancel host for maintenance")
Expand Down
21 changes: 21 additions & 0 deletions cloudstack/cloudstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"net/url"
"regexp"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -67,6 +68,26 @@ func (e *CSError) Error() error {
return fmt.Errorf("CloudStack API error %d (CSExceptionErrorCode: %d): %s", e.ErrorCode, e.CSErrorCode, e.ErrorText)
}

type UUID string

func (c UUID) MarshalJSON() ([]byte, error) {
return json.Marshal(string(c))
}

func (c *UUID) UnmarshalJSON(data []byte) error {
value := strings.Trim(string(data), "\"")
if strings.HasPrefix(string(data), "\"") {
*c = UUID(value)
return nil
}
_, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
*c = UUID(value)
return nil
}

type CloudStackClient struct {
HTTPGETOnly bool // If `true` only use HTTP GET calls

Expand Down
32 changes: 32 additions & 0 deletions cloudstack/cloudstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,35 @@ func TestCreateSyncClient(t *testing.T) {
t.Errorf("Failed to create Cloudstack Client")
}
}

type UUIDStruct struct {
Value UUID `json:"value"`
}

func TestUUID(t *testing.T) {
valLong := `{"value": 4801878}`
valString := `{"value": "994801878"}`
valBool := `{"value": false}`
res := UUIDStruct{}

res.Value = ""
if err := json.Unmarshal([]byte(valLong), &res); err != nil {
t.Errorf("could not unserialize long into UUID: %s", err)
}
if res.Value != "4801878" {
t.Errorf("unepected value '%s', expecting 4801878", res.Value)
}

res.Value = ""
if err := json.Unmarshal([]byte(valString), &res); err != nil {
t.Errorf("could not unserialize string into UUID: %s", err)
}
if res.Value != "994801878" {
t.Errorf("unepected value '%s', expecting 994801878", res.Value)
}

res.Value = ""
if err := json.Unmarshal([]byte(valBool), &res); err == nil {
t.Errorf("missing expected error when serializing bool into UUID")
}
}
35 changes: 35 additions & 0 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ var nestedResponse = map[string]string{
"getUploadParamsForVolume": "getuploadparams",
}

// longToStringConvertedParams is a prefilled map with the list of
// response fields that migrated from long to string within
// the current major baseline. This fields will be parsed from
// json as string and then fallback on long.
var longToStringConvertedParams = map[string]bool{
"managementserverid": true,
}

// We prefill this one value to make sure it is not
// created twice, as this is also a top level type.
var typeNames = map[string]bool{"Nic": true}
Expand Down Expand Up @@ -301,6 +309,27 @@ func (as *allServices) GeneralCode() ([]byte, error) {
pn(" return fmt.Errorf(\"CloudStack API error %%d (CSExceptionErrorCode: %%d): %%s\", e.ErrorCode, e.CSErrorCode, e.ErrorText)")
pn("}")
pn("")

pn("type UUID string")
pn("")
pn("func (c UUID) MarshalJSON() ([]byte, error) {")
pn(" return json.Marshal(string(c))")
pn("}")
pn("")
pn("func (c *UUID) UnmarshalJSON(data []byte) error {")
pn(" value := strings.Trim(string(data), \"\\\"\")")
pn(" if strings.HasPrefix(string(data), \"\\\"\") {")
pn(" *c = UUID(value)")
pn(" return nil")
pn(" }")
pn(" _, err := strconv.ParseInt(value, 10, 64)")
pn(" if err != nil {")
pn(" return err")
pn(" }")
pn(" *c = UUID(value)")
pn(" return nil")
pn("}")

pn("type CloudStackClient struct {")
pn(" HTTPGETOnly bool // If `true` only use HTTP GET calls")
pn("")
Expand Down Expand Up @@ -1802,7 +1831,13 @@ func sourceDir() (string, error) {
}

func mapType(aName string, pName string, pType string) string {
if _, ok := longToStringConvertedParams[pName]; ok {
pType = "UUID"
}

switch pType {
case "UUID":
return "UUID"
case "boolean":
return "bool"
case "short", "int", "integer":
Expand Down

0 comments on commit 71cd5ea

Please sign in to comment.