From 5bab9013acd2fbd7ee6c74a8d1539a1a24478e5b Mon Sep 17 00:00:00 2001 From: Samuel Allan Date: Wed, 10 Apr 2024 13:52:52 +0930 Subject: [PATCH 1/2] Handle nova api version > 2.87 for hypervisor fixes: #3026 --- openstack/compute/v2/hypervisors/results.go | 76 ++++++++++++--------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/openstack/compute/v2/hypervisors/results.go b/openstack/compute/v2/hypervisors/results.go index 2e8d244763..ee6046c6c0 100644 --- a/openstack/compute/v2/hypervisors/results.go +++ b/openstack/compute/v2/hypervisors/results.go @@ -158,27 +158,31 @@ func (r *Hypervisor) UnmarshalJSON(b []byte) error { *r = Hypervisor(s.tmp) - // Newer versions return the CPU info as the correct type. - // Older versions return the CPU info as a string and need to be - // unmarshalled by the json parser. - var tmpb []byte - - switch t := s.CPUInfo.(type) { - case string: - tmpb = []byte(t) - case map[string]any: - tmpb, err = json.Marshal(t) - if err != nil { - return err + // cpu_info doesn't exist after api version 2.87, + // see https://docs.openstack.org/api-ref/compute/#id288 + if s.CPUInfo != nil { + // api versions 2.28 to 2.87 return the CPU info as the correct type. + // api versions < 2.28 return the CPU info as a string and need to be + // unmarshalled by the json parser. + var tmpb []byte + + switch t := s.CPUInfo.(type) { + case string: + tmpb = []byte(t) + case map[string]any: + tmpb, err = json.Marshal(t) + if err != nil { + return err + } + default: + return fmt.Errorf("CPUInfo has unexpected type: %T", t) } - default: - return fmt.Errorf("CPUInfo has unexpected type: %T", t) - } - if len(tmpb) != 0 { - err = json.Unmarshal(tmpb, &r.CPUInfo) - if err != nil { - return err + if len(tmpb) != 0 { + err = json.Unmarshal(tmpb, &r.CPUInfo) + if err != nil { + return err + } } } @@ -193,22 +197,28 @@ func (r *Hypervisor) UnmarshalJSON(b []byte) error { return fmt.Errorf("Hypervisor version has unexpected type: %T", t) } - switch t := s.FreeDiskGB.(type) { - case int: - r.FreeDiskGB = t - case float64: - r.FreeDiskGB = int(t) - default: - return fmt.Errorf("Free disk GB has unexpected type: %T", t) + // free_disk_gb doesn't exist after api version 2.87 + if s.FreeDiskGB != nil { + switch t := s.FreeDiskGB.(type) { + case int: + r.FreeDiskGB = t + case float64: + r.FreeDiskGB = int(t) + default: + return fmt.Errorf("Free disk GB has unexpected type: %T", t) + } } - switch t := s.LocalGB.(type) { - case int: - r.LocalGB = t - case float64: - r.LocalGB = int(t) - default: - return fmt.Errorf("Local GB has unexpected type: %T", t) + // local_gb doesn't exist after api version 2.87 + if s.LocalGB != nil { + switch t := s.LocalGB.(type) { + case int: + r.LocalGB = t + case float64: + r.LocalGB = int(t) + default: + return fmt.Errorf("Local GB has unexpected type: %T", t) + } } // OpenStack Compute service returns ID in string representation since From 91f66ee37be7f7b2a0386881e8091d829640db66 Mon Sep 17 00:00:00 2001 From: Samuel Allan Date: Thu, 18 Jul 2024 07:35:37 +0930 Subject: [PATCH 2/2] Add unit test --- .../v2/hypervisors/testing/fixtures_test.go | 68 +++++++++++++++++++ .../v2/hypervisors/testing/requests_test.go | 12 ++++ 2 files changed, 80 insertions(+) diff --git a/openstack/compute/v2/hypervisors/testing/fixtures_test.go b/openstack/compute/v2/hypervisors/testing/fixtures_test.go index 1942c842e0..a969f1f825 100644 --- a/openstack/compute/v2/hypervisors/testing/fixtures_test.go +++ b/openstack/compute/v2/hypervisors/testing/fixtures_test.go @@ -346,6 +346,36 @@ const HypervisorGetEmptyCPUInfoBody = ` } ` +// HypervisorAfterV287ResponseBody represents a raw hypervisor GET result with +// missing cpu_info, free_disk_gb, local_gb as seen after v2.87 +const HypervisorAfterV287ResponseBody = ` +{ + "hypervisor":{ + "current_workload":0, + "status":"enabled", + "state":"up", + "disk_available_least":0, + "host_ip":"1.1.1.1", + "free_ram_mb":7680, + "hypervisor_hostname":"fake-mini", + "hypervisor_type":"fake", + "hypervisor_version":2002000, + "id":"c48f6247-abe4-4a24-824e-ea39e108874f", + "local_gb_used":0, + "memory_mb":8192, + "memory_mb_used":512, + "running_vms":0, + "service":{ + "host":"e6a37ee802d74863ab8b91ade8f12a67", + "id":"9c2566e7-7a54-4777-a1ae-c2662f0c407c", + "disabled_reason":null + }, + "vcpus":1, + "vcpus_used":0 + } +} +` + // HypervisorUptimeBody represents a raw hypervisor uptime request result with // Pike+ release. const HypervisorUptimeBody = ` @@ -492,6 +522,7 @@ var ( } HypervisorEmptyCPUInfo = hypervisors.Hypervisor{ + CPUInfo: hypervisors.CPUInfo{}, CurrentWorkload: 0, Status: "enabled", State: "up", @@ -517,6 +548,33 @@ var ( VCPUsUsed: 0, } + HypervisorAfterV287Response = hypervisors.Hypervisor{ + CPUInfo: hypervisors.CPUInfo{}, + CurrentWorkload: 0, + Status: "enabled", + State: "up", + DiskAvailableLeast: 0, + HostIP: "1.1.1.1", + FreeDiskGB: 0, + FreeRamMB: 7680, + HypervisorHostname: "fake-mini", + HypervisorType: "fake", + HypervisorVersion: 2002000, + ID: "c48f6247-abe4-4a24-824e-ea39e108874f", + LocalGB: 0, + LocalGBUsed: 0, + MemoryMB: 8192, + MemoryMBUsed: 512, + RunningVMs: 0, + Service: hypervisors.Service{ + Host: "e6a37ee802d74863ab8b91ade8f12a67", + ID: "9c2566e7-7a54-4777-a1ae-c2662f0c407c", + DisabledReason: "", + }, + VCPUs: 1, + VCPUsUsed: 0, + } + HypervisorsStatisticsExpected = hypervisors.Statistics{ Count: 1, CurrentWorkload: 0, @@ -604,6 +662,16 @@ func HandleHypervisorGetEmptyCPUInfoSuccessfully(t *testing.T) { }) } +func HandleHypervisorAfterV287ResponseSuccessfully(t *testing.T) { + testhelper.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { + testhelper.TestMethod(t, r, "GET") + testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, HypervisorAfterV287ResponseBody) + }) +} + func HandleHypervisorUptimeSuccessfully(t *testing.T) { testhelper.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID+"/uptime", func(w http.ResponseWriter, r *http.Request) { testhelper.TestMethod(t, r, "GET") diff --git a/openstack/compute/v2/hypervisors/testing/requests_test.go b/openstack/compute/v2/hypervisors/testing/requests_test.go index 900eadc78b..493e8138d1 100644 --- a/openstack/compute/v2/hypervisors/testing/requests_test.go +++ b/openstack/compute/v2/hypervisors/testing/requests_test.go @@ -148,6 +148,18 @@ func TestGetHypervisorEmptyCPUInfo(t *testing.T) { testhelper.CheckDeepEquals(t, &expected, actual) } +func TestGetHypervisorAfterV287Response(t *testing.T) { + testhelper.SetupHTTP() + defer testhelper.TeardownHTTP() + HandleHypervisorAfterV287ResponseSuccessfully(t) + + expected := HypervisorAfterV287Response + + actual, err := hypervisors.Get(context.TODO(), client.ServiceClient(), expected.ID).Extract() + testhelper.AssertNoErr(t, err) + testhelper.CheckDeepEquals(t, &expected, actual) +} + func TestHypervisorsUptime(t *testing.T) { testhelper.SetupHTTP() defer testhelper.TeardownHTTP()